/*
* 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 <inttypes.h>
#include <string.h>
#include <stdint.h>
#include <sys/endian.h>
#include <variant/variant.h>
#include <eventnums.h>
#include <plat/taggedPtr.h>
#include <plat/plat.h>
#include <plat/wdt.h>
#include <nanohub/crc.h>
#include <nanohub/rsa.h>
#include <nanohub/nanohub.h>
#include <bl.h>
#include <atomicBitset.h>
#include <atomic.h>
#include <hostIntf.h>
#include <hostIntf_priv.h>
#include <nanohubCommand.h>
#include <nanohubPacket.h>
#include <eeData.h>
#include <seos.h>
#include <seos_priv.h>
#include <util.h>
#include <mpu.h>
#include <heap.h>
#include <slab.h>
#include <sensType.h>
#include <timer.h>
#include <appSec.h>
#include <cpu.h>
#include <cpu/cpuMath.h>
#include <algos/ap_hub_sync.h>
#include <sensors_priv.h>
#include <chre.h>
#define NANOHUB_COMMAND(_reason, _fastHandler, _handler, _minReqType, _maxReqType) \
{ .reason = _reason, .fastHandler = _fastHandler, .handler = _handler, \
.minDataLen = sizeof(_minReqType), .maxDataLen = sizeof(_maxReqType) }
#define NANOHUB_HAL_LEGACY_COMMAND(_msg, _handler) \
{ .msg = _msg, .handler = _handler }
#define NANOHUB_HAL_COMMAND(_msg, _handler, _minReqType, _maxReqType) \
{ .msg = _msg, .handler = _handler, \
.minDataLen = sizeof(_minReqType), .maxDataLen = sizeof(_maxReqType) }
// maximum number of bytes to feed into appSecRxData at once
// The bigger the number, the more time we block other event processing
// appSecRxData only feeds 16 bytes at a time into writeCbk, so large
// numbers don't buy us that much
#define MAX_APP_SEC_RX_DATA_LEN 64
#define REQUIRE_SIGNED_IMAGE true
#define DEBUG_APHUB_TIME_SYNC false
#if DEBUG_APHUB_TIME_SYNC
static void syncDebugAdd(uint64_t, uint64_t);
#endif
struct DownloadState
{
struct AppSecState *appSecState;
uint32_t size; // document size, as reported by client
uint32_t srcOffset; // bytes received from client
uint32_t dstOffset; // bytes sent to flash
struct AppHdr *start; // start of flash segment, where to write
uint32_t crc; // document CRC-32, as reported by client
uint32_t srcCrc; // current state of CRC-32 we generate from input
uint8_t data[NANOHUB_PACKET_PAYLOAD_MAX];
uint8_t len;
uint8_t lenLeft;
uint8_t chunkReply;
bool erase;
bool eraseScheduled;
};
static struct DownloadState *mDownloadState;
static AppSecErr mAppSecStatus;
static struct AppHdr *mApp;
static struct SlabAllocator *mEventSlab;
static struct HostIntfDataBuffer mTxCurr, mTxNext;
static uint8_t mTxCurrLength, mTxNextLength;
static uint8_t mPrefetchActive, mPrefetchTx;
static uint32_t mTxWakeCnt[2];
static struct ApHubSync mTimeSync;
static inline bool isSensorEvent(uint32_t evtType)
{
return evtType > EVT_NO_FIRST_SENSOR_EVENT && evtType <= EVT_NO_FIRST_SENSOR_EVENT + SENS_TYPE_LAST_USER;
}
static void slabFree(void *ptr)
{
slabAllocatorFree(mEventSlab, ptr);
}
void nanohubInitCommand(void)
{
mEventSlab = slabAllocatorNew(NANOHUB_PACKET_PAYLOAD_MAX-sizeof(__le32), 4, 2);
}
static inline uint64_t unaligned_u64(uint64_t *val) {
uint64_t local;
memcpy(&local, val, sizeof(local));
return local;
}
static inline uint32_t unaligned_u32(uint32_t *val) {
uint32_t local;
memcpy(&local, val, sizeof(local));
return local;
}
static uint32_t getOsHwVersion(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
{
struct NanohubOsHwVersionsResponse *resp = tx;
resp->hwType = htole16(platHwType());
resp->hwVer = htole16(platHwVer());
resp->blVer = htole16(platBlVer());
resp->osVer = htole16(OS_VER);
resp->variantVer = htole32(VARIANT_VER);
return sizeof(*resp);
}
static uint32_t getAppVersion(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
{
struct NanohubAppVersionsRequest *req = rx;
struct NanohubAppVersionsResponse *resp = tx;
uint32_t appIdx, appVer, appSize;
if (osAppInfoById(le64toh(unaligned_u64(&req->appId)), &appIdx, &appVer, &appSize)) {
resp->appVer = htole32(appVer);
return sizeof(*resp);
}
return 0;
}
static uint32_t queryAppInfo(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
{
struct NanohubAppInfoRequest *req = rx;
struct NanohubAppInfoResponse *resp = tx;
uint64_t appId;
uint32_t appVer, appSize;
if (osAppInfoByIndex(le32toh(unaligned_u32(&req->appIdx)), &appId, &appVer, &appSize)) {
resp->appId = htole64(appId);
resp->appVer = htole32(appVer);
resp->appSize = htole32(appSize);
return sizeof(*resp);
}
return 0;
}
static AppSecErr writeCbk(const void *data, uint32_t len)
{
AppSecErr ret = APP_SEC_BAD;
if (osWriteShared((uint8_t*)(mDownloadState->start) + mDownloadState->dstOffset, data, len)) {
ret = APP_SEC_NO_ERROR;
mDownloadState->dstOffset += len;
}
return ret;
}
static AppSecErr pubKeyFindCbk(const uint32_t *gotKey, bool *foundP)
{
const uint32_t *ptr;
uint32_t numKeys, i;
*foundP = false;
ptr = BL.blGetPubKeysInfo(&numKeys);
for (i = 0; ptr && i < numKeys; i++, ptr += RSA_LIMBS) {
if (!memcmp(gotKey, ptr, RSA_BYTES)) {
*foundP = true;
break;
}
}
return APP_SEC_NO_ERROR;
}
static AppSecErr osSecretKeyLookup(uint64_t keyId, void *keyBuf)
{
struct SeosEedataEncrKeyData kd;
void *state = NULL;
while(1) {
uint32_t sz = sizeof(struct SeosEedataEncrKeyData);
if (!eeDataGetAllVersions(EE_DATA_NAME_ENCR_KEY, &kd, &sz, &state))
break;
if (sz == sizeof(struct SeosEedataEncrKeyData) && kd.keyID == keyId) {
if (keyBuf)
memcpy(keyBuf, kd.key, sizeof(kd.key));
return APP_SEC_NO_ERROR;
}
}
return APP_SEC_KEY_NOT_FOUND;
}
static AppSecErr osSecretKeyDelete(uint64_t keyId)
{
struct SeosEedataEncrKeyData kd;
void *state = NULL;
bool good = true;
int count = 0;
while(1) {
uint32_t sz = sizeof(struct SeosEedataEncrKeyData);
void *addr = eeDataGetAllVersions(EE_DATA_NAME_ENCR_KEY, &kd, &sz, &state);
if (!addr)
break;
if (sz == sizeof(kd) && kd.keyID == keyId) {
good = eeDataEraseOldVersion(EE_DATA_NAME_ENCR_KEY, addr) && good;
count++;
}
}
return count == 0 ? APP_SEC_KEY_NOT_FOUND : good ? APP_SEC_NO_ERROR : APP_SEC_BAD;
}
static AppSecErr osSecretKeyAdd(uint64_t keyId, void *keyBuf)
{
struct SeosEedataEncrKeyData kd;
// do not add key if it already exists
if (osSecretKeyLookup(keyId, NULL) != APP_SEC_KEY_NOT_FOUND)
return APP_SEC_BAD;
memcpy(&kd.key, keyBuf, 32);
kd.keyID = keyId;
return eeDataSet(EE_DATA_NAME_ENCR_KEY, &kd, sizeof(kd)) ? APP_SEC_NO_ERROR : APP_SEC_BAD;
}
static void freeDownloadState()
{
if (mDownloadState->appSecState)
appSecDeinit(mDownloadState->appSecState);
heapFree(mDownloadState);
mDownloadState = NULL;
}
static bool resetDownloadState(bool initial, bool erase)
{
bool doCreate = true;
mAppSecStatus = APP_SEC_NO_ERROR;
if (mDownloadState->appSecState)
appSecDeinit(mDownloadState->appSecState);
mDownloadState->appSecState = appSecInit(writeCbk, pubKeyFindCbk, osSecretKeyLookup, REQUIRE_SIGNED_IMAGE);
mDownloadState->srcOffset = 0;
mDownloadState->srcCrc = ~0;
if (!initial) {
// if no data was written, we can reuse the same segment
if (mDownloadState->dstOffset)
osAppSegmentClose(mDownloadState->start, mDownloadState->dstOffset, SEG_ST_ERASED);
else
doCreate = false;
}
mDownloadState->dstOffset = 0;
if (doCreate)
mDownloadState->start = osAppSegmentCreate(mDownloadState->size);
if (!mDownloadState->start) {
if (erase)
mDownloadState->erase = true;
else
return false;
}
return true;
}
static bool doStartFirmwareUpload(struct NanohubStartFirmwareUploadRequest *req, bool erase)
{
if (!mDownloadState) {
mDownloadState = heapAlloc(sizeof(struct DownloadState));
if (!mDownloadState)
return false;
else
memset(mDownloadState, 0x00, sizeof(struct DownloadState));
}
mDownloadState->size = le32toh(req->size);
mDownloadState->crc = le32toh(req->crc);
mDownloadState->chunkReply = NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED;
return resetDownloadState(true, erase);
}
static uint32_t startFirmwareUpload(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
{
struct NanohubStartFirmwareUploadRequest *req = rx;
struct NanohubStartFirmwareUploadResponse *resp = tx;
resp->accepted = doStartFirmwareUpload(req, true);
return sizeof(*resp);
}
static void deferredUpdateOs(void *cookie)
{
const struct AppHdr *app = cookie;
struct OsUpdateHdr *os = (struct OsUpdateHdr *)(&(app->hdr) + 1);
uint32_t uploadStatus = OS_UPDT_HDR_CHECK_FAILED;
uint8_t marker = OS_UPDT_MARKER_DOWNLOADED;
struct Segment *seg = osGetSegment(app);
uint32_t segSize = osSegmentGetSize(seg);
osLog(LOG_INFO, "%s: checking OS image @ %p\n", __func__, os);
// some sanity checks before asking BL to do image lookup
hostIntfSetBusy(true);
if (segSize >= (sizeof(*app) + sizeof(*os)) && segSize > os->size) {
if (osWriteShared(&os->marker, &marker, sizeof(os->marker))) {
wdtDisableClk();
uploadStatus = BL.blVerifyOsUpdate();
wdtEnableClk();
} else {
osLog(LOG_ERROR, "%s: could not set marker on OS image\n", __func__);
}
}
hostIntfSetBusy(false);
osLog(LOG_INFO, "%s: status=%" PRIu32 "\n", __func__, uploadStatus);
}
static AppSecErr updateKey(const struct AppHdr *app)
{
AppSecErr ret;
struct KeyInfo *ki = (struct KeyInfo *)(&(app->hdr) + 1);
uint8_t *data = (uint8_t *)(ki + 1);
uint64_t keyId = KEY_ID_MAKE(APP_ID_GET_VENDOR(app->hdr.appId), ki->id);
const char *op;
if ((app->hdr.fwFlags & FL_KEY_HDR_DELETE) != 0) {
// removing existing key
ret = osSecretKeyDelete(keyId);
op = "Removing";
} else {
// adding new key
ret = osSecretKeyAdd(keyId, data);
op = "Adding";
}
osLog(LOG_INFO, "%s: %s key: id=%016" PRIX64 "; ret=%" PRIu32 "\n",
__func__, op, keyId, ret);
return ret;
}
static uint32_t appSecErrToNanohubReply(AppSecErr status)
{
uint32_t reply;
switch (status) {
case APP_SEC_NO_ERROR:
reply = NANOHUB_FIRMWARE_UPLOAD_SUCCESS;
break;
case APP_SEC_KEY_NOT_FOUND:
reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_KEY_NOT_FOUND;
break;
case APP_SEC_HEADER_ERROR:
reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_HEADER_ERROR;
break;
case APP_SEC_TOO_MUCH_DATA:
reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_TOO_MUCH_DATA;
break;
case APP_SEC_TOO_LITTLE_DATA:
reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_TOO_LITTLE_DATA;
break;
case APP_SEC_SIG_VERIFY_FAIL:
reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_SIG_VERIFY_FAIL;
break;
case APP_SEC_SIG_DECODE_FAIL:
reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_SIG_DECODE_FAIL;
break;
case APP_SEC_SIG_ROOT_UNKNOWN:
reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_SIG_ROOT_UNKNOWN;
break;
case APP_SEC_MEMORY_ERROR:
reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_MEMORY_ERROR;
break;
case APP_SEC_INVALID_DATA:
reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_INVALID_DATA;
break;
case APP_SEC_VERIFY_FAILED:
reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_VERIFY_FAILED;
break;
default:
reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_BAD;
break;
}
return reply;
}
static uint32_t firmwareFinish(bool valid)
{
struct AppHdr *app;
struct Segment *storageSeg;
uint32_t segState;
uint32_t ret = NANOHUB_FIRMWARE_UPLOAD_SUCCESS;
if (!mDownloadState) {
ret = appSecErrToNanohubReply(mAppSecStatus);
osLog(LOG_INFO, "%s: no DL status; decoding secure status: %" PRIu32 "\n", __func__, ret);
return ret;
}
app = mDownloadState->start;
storageSeg = osGetSegment(app);
if (mAppSecStatus == APP_SEC_NO_ERROR && valid) {
osLog(LOG_INFO, "%s: Secure verification passed\n", __func__);
if (storageSeg->state != SEG_ST_RESERVED ||
mDownloadState->size < sizeof(struct FwCommonHdr) ||
app->hdr.magic != APP_HDR_MAGIC ||
app->hdr.fwVer != APP_HDR_VER_CUR) {
segState = SEG_ST_ERASED;
osLog(LOG_INFO, "%s: Header verification failed\n", __func__);
} else {
segState = SEG_ST_VALID;
}
} else {
segState = SEG_ST_ERASED;
osLog(LOG_INFO, "%s: Secure verification failed: valid=%d; status=%" PRIu32 "\n", __func__, valid, mAppSecStatus);
}
if (!osAppSegmentClose(app, mDownloadState->dstOffset, segState)) {
osLog(LOG_INFO, "%s: Failed to close segment\n", __func__);
valid = false;
mApp = NULL;
} else {
segState = osAppSegmentGetState(app);
mApp = app;
valid = (segState == SEG_ST_VALID);
}
osLog(LOG_INFO, "Loaded %s image type %" PRIu8 ": %" PRIu32
" bytes @ %p; state=%02" PRIX32 "; crc=%08" PRIX32 "\n",
valid ? "valid" : "invalid",
app->hdr.payInfoType, mDownloadState->size,
mDownloadState->start, segState,
mApp ? osAppSegmentGetCrc(mApp) : 0xFFFFFFFF);
freeDownloadState(); // no more access to mDownloadState
if (!valid)
ret = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_BAD;
// take extra care about some special payload types
if (ret == NANOHUB_FIRMWARE_UPLOAD_SUCCESS) {
switch(app->hdr.payInfoType) {
case LAYOUT_OS:
osLog(LOG_INFO, "Performing OS update\n");
// we want to give this message a chance to reach host before we start erasing stuff
osDefer(deferredUpdateOs, (void*)app, false);
break;
case LAYOUT_KEY:
ret = appSecErrToNanohubReply(updateKey(app));
break;
}
}
if (ret != NANOHUB_FIRMWARE_UPLOAD_SUCCESS || (app->hdr.fwFlags & FL_APP_HDR_VOLATILE)) {
if ((app->hdr.fwFlags & FL_APP_HDR_SECURE))
osAppWipeData((struct AppHdr*)app);
osAppSegmentSetState(app, SEG_ST_ERASED);
}
// if any error happened after we downloaded and verified image, we say it is unknown fault
// we don't have download status, so e have to save returned value in secure status field, because
// host may request the same status multiple times
if (ret != NANOHUB_FIRMWARE_UPLOAD_SUCCESS)
mAppSecStatus = APP_SEC_BAD;
return ret;
}
static void firmwareErase(void *cookie)
{
if (mDownloadState->erase == true) {
osLog(LOG_INFO, "%s: erasing shared area\n", __func__);
osEraseShared();
mDownloadState->start = osAppSegmentCreate(mDownloadState->size);
if (!mDownloadState->start)
firmwareFinish(false);
mDownloadState->erase = false;
hostIntfSetInterrupt(NANOHUB_INT_CMD_WAIT);
}
mDownloadState->eraseScheduled = false;
}
SET_PACKED_STRUCT_MODE_ON
struct FirmwareWriteCookie
{
uint32_t evtType;
union {
#ifdef LEGACY_HAL_ENABLED
struct NanohubHalLegacyContUploadTx respLegacy;
#endif
struct NanohubHalContUploadTx resp;
};
} ATTRIBUTE_PACKED;
SET_PACKED_STRUCT_MODE_OFF
static void writeCookieFree(void *ptr)
{
struct FirmwareWriteCookie *buf = container_of(ptr, struct FirmwareWriteCookie, resp);
heapFree(buf);
}
static void firmwareWrite(void *cookie)
{
bool valid;
bool finished = false;
struct FirmwareWriteCookie *resp = cookie;
// only check crc when cookie is NULL (write came from kernel, not HAL)
bool checkCrc = !cookie;
if (mAppSecStatus == APP_SEC_NEED_MORE_TIME) {
mAppSecStatus = appSecDoSomeProcessing(mDownloadState->appSecState);
} else if (mDownloadState->lenLeft) {
const uint8_t *data = mDownloadState->data + mDownloadState->len - mDownloadState->lenLeft;
uint32_t len = mDownloadState->lenLeft, lenLeft, lenRem = 0;
if (len > MAX_APP_SEC_RX_DATA_LEN) {
lenRem = len - MAX_APP_SEC_RX_DATA_LEN;
len = MAX_APP_SEC_RX_DATA_LEN;
}
mAppSecStatus = appSecRxData(mDownloadState->appSecState, data, len, &lenLeft);
mDownloadState->lenLeft = lenLeft + lenRem;
}
valid = (mAppSecStatus == APP_SEC_NO_ERROR);
if (mAppSecStatus == APP_SEC_NEED_MORE_TIME || mDownloadState->lenLeft) {
osDefer(firmwareWrite, cookie, false);
return;
} else if (valid) {
if (mDownloadState->srcOffset == mDownloadState->size) {
mAppSecStatus = appSecRxDataOver(mDownloadState->appSecState);
finished = true;
valid = !checkCrc || mDownloadState->crc == ~mDownloadState->srcCrc;
} else if (mDownloadState->srcOffset > mDownloadState->size) {
valid = false;
}
}
if (!valid)
finished = true;
if (finished) {
if (firmwareFinish(valid) != NANOHUB_FIRMWARE_UPLOAD_SUCCESS)
valid = false;
}
if (resp) {
if (resp->evtType == EVT_APP_TO_HOST) {
#ifdef LEGACY_HAL_ENABLED
resp->respLegacy.success = valid;
osEnqueueEvtOrFree(EVT_APP_TO_HOST, &resp->respLegacy, writeCookieFree);
#endif
} else {
resp->resp.ret.status = !valid;
osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, &resp->resp, writeCookieFree);
}
}
}
static uint32_t doFirmwareChunk(uint8_t *data, uint32_t offset, uint32_t len, void *cookie)
{
uint32_t reply, ret;
if (!mDownloadState) {
reply = NANOHUB_FIRMWARE_CHUNK_REPLY_CANCEL_NO_RETRY;
} else if (mAppSecStatus == APP_SEC_NEED_MORE_TIME || mDownloadState->lenLeft) {
reply = NANOHUB_FIRMWARE_CHUNK_REPLY_RESEND;
} else if (mDownloadState->chunkReply != NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED) {
reply = mDownloadState->chunkReply;
firmwareFinish(false);
} else {
if (mDownloadState->erase == true) {
reply = NANOHUB_FIRMWARE_CHUNK_REPLY_WAIT;
if (!mDownloadState->eraseScheduled) {
ret = osExtAppStopAppsByAppId(APP_ID_ANY);
osLog(LOG_INFO, "%s: unloaded apps, ret=%08lx\n", __func__, ret);
mDownloadState->eraseScheduled = osDefer(firmwareErase, NULL, false);
}
} else if (!mDownloadState->start) {
// this means we can't allocate enough space even after we did erase
reply = NANOHUB_FIRMWARE_CHUNK_REPLY_CANCEL_NO_RETRY;
firmwareFinish(false);
} else if (offset != mDownloadState->srcOffset) {
reply = NANOHUB_FIRMWARE_CHUNK_REPLY_RESTART;
resetDownloadState(false, true);
} else {
if (!cookie)
mDownloadState->srcCrc = soft_crc32(data, len, mDownloadState->srcCrc);
mDownloadState->srcOffset += len;
memcpy(mDownloadState->data, data, len);
mDownloadState->lenLeft = mDownloadState->len = len;
reply = NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED;
osDefer(firmwareWrite, cookie, false);
}
}
return reply;
}
static uint32_t firmwareChunk(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
{
struct NanohubFirmwareChunkRequest *req = rx;
struct NanohubFirmwareChunkResponse *resp = tx;
uint32_t offset = le32toh(req->offset);
uint8_t len = rx_len - sizeof(req->offset);
resp->chunkReply = doFirmwareChunk(req->data, offset, len, NULL);
return sizeof(*resp);
}
static uint32_t doFinishFirmwareUpload(uint32_t *addr, uint32_t *crc)
{
uint32_t reply;
if (!mDownloadState) {
reply = appSecErrToNanohubReply(mAppSecStatus);
if (addr) {
if (mApp)
*addr = (uint32_t)mApp;
else
*addr = 0xFFFFFFFF;
}
if (crc) {
if (mApp)
*crc = osAppSegmentGetCrc(mApp);
else
*crc = 0xFFFFFFFF;
}
} else if (mDownloadState->srcOffset == mDownloadState->size) {
reply = NANOHUB_FIRMWARE_UPLOAD_PROCESSING;
} else {
reply = firmwareFinish(false);
}
return reply;
}
static uint32_t finishFirmwareUpload(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
{
struct NanohubFinishFirmwareUploadResponse *resp = tx;
resp->uploadReply = doFinishFirmwareUpload(NULL, NULL);
if (resp->uploadReply != NANOHUB_FIRMWARE_UPLOAD_PROCESSING)
osLog(LOG_INFO, "%s: reply=%" PRIu8 "\n", __func__, resp->uploadReply);
return sizeof(*resp);
}
static uint32_t getInterrupt(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
{
struct NanohubGetInterruptRequest *req = rx;
struct NanohubGetInterruptResponse *resp = tx;
int i;
if (rx_len == sizeof(struct NanohubGetInterruptRequest)) {
for (i = 0; i < HOSTINTF_MAX_INTERRUPTS; i++) {
if (req->clear[i/32] & (1UL << (i & 31)))
hostIntfClearInterrupt(i);
}
}
hostIntfCopyInterrupts(resp->interrupts, HOSTINTF_MAX_INTERRUPTS);
return sizeof(*resp);
}
static uint32_t maskInterrupt(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
{
struct NanohubMaskInterruptRequest *req = rx;
struct NanohubMaskInterruptResponse *resp = tx;
hostIntfSetInterruptMask(req->interrupt);
resp->accepted = true;
return sizeof(*resp);
}
static uint32_t unmaskInterrupt(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
{
struct NanohubUnmaskInterruptRequest *req = rx;
struct NanohubUnmaskInterruptResponse *resp = tx;
hostIntfClearInterruptMask(req->interrupt);
resp->accepted = true;
return sizeof(*resp);
}
static void addDelta(struct ApHubSync *sync, uint64_t apTime, uint64_t hubTime)
{
#if DEBUG_APHUB_TIME_SYNC
syncDebugAdd(apTime, hubTime);
#endif
apHubSyncAddDelta(sync, apTime, hubTime);
}
static int64_t getAvgDelta(struct ApHubSync *sync)
{
return apHubSyncGetDelta(sync, sensorGetTime());
}
static int fillBuffer(void *tx, uint32_t totLength, uint32_t *wakeup, uint32_t *nonwakeup)
{
struct HostIntfDataBuffer *packet = &mTxNext;
struct HostIntfDataBuffer *firstPacket = tx;
uint8_t *buf = tx;
uint32_t length;
uint32_t prevWakeup, prevNonWakeup;
prevWakeup = *wakeup;
prevNonWakeup = *nonwakeup;
while (hostIntfPacketDequeue(&mTxNext, wakeup, nonwakeup)) {
length = packet->length + sizeof(packet->evtType);
if (packet->sensType == SENS_TYPE_INVALID) {
switch (packet->dataType) {
case HOSTINTF_DATA_TYPE_APP_TO_HOST:
packet->evtType = htole32(EVT_APP_TO_HOST);
break;
case HOSTINTF_DATA_TYPE_RESET_REASON:
packet->evtType = htole32(EVT_RESET_REASON);
break;
case HOSTINTF_DATA_TYPE_APP_TO_SENSOR_HAL:
packet->evtType = htole32(EVT_APP_TO_SENSOR_HAL_DATA);
break;
#ifdef DEBUG_LOG_EVT
case HOSTINTF_DATA_TYPE_LOG:
packet->evtType = htole32(HOST_EVT_DEBUG_LOG);
break;
#endif
default:
packet->evtType = htole32(0x00000000);
break;
}
} else {
packet->evtType = htole32(EVT_NO_FIRST_SENSOR_EVENT + packet->sensType);
if (packet->referenceTime)
packet->referenceTime += getAvgDelta(&mTimeSync);
if (*wakeup > 0)
packet->firstSample.interrupt = NANOHUB_INT_WAKEUP;
}
if ((!totLength || (isSensorEvent(firstPacket->evtType) && isSensorEvent(packet->evtType))) &&
totLength + length <= sizeof(struct HostIntfDataBuffer)) {
memcpy(buf + totLength, &mTxNext, length);
totLength += length;
if (isSensorEvent(packet->evtType) && packet->firstSample.interrupt == NANOHUB_INT_WAKEUP)
firstPacket->firstSample.interrupt = NANOHUB_INT_WAKEUP;
} else {
mTxNextLength = length;
*wakeup = prevWakeup;
*nonwakeup = prevNonWakeup;
break;
}
prevWakeup = *wakeup;
prevNonWakeup = *nonwakeup;
}
return totLength;
}
static void updateInterrupts(void)
{
uint32_t wakeup = atomicRead32bits(&mTxWakeCnt[0]);
uint32_t nonwakeup = atomicRead32bits(&mTxWakeCnt[1]);
bool wakeupStatus = hostIntfGetInterrupt(NANOHUB_INT_WAKEUP);
bool nonwakeupStatus = hostIntfGetInterrupt(NANOHUB_INT_NONWAKEUP);
if (!wakeup && wakeupStatus)
hostIntfClearInterrupt(NANOHUB_INT_WAKEUP);
else if (wakeup && !wakeupStatus)
hostIntfSetInterrupt(NANOHUB_INT_WAKEUP);
if (!nonwakeup && nonwakeupStatus)
hostIntfClearInterrupt(NANOHUB_INT_NONWAKEUP);
else if (nonwakeup && !nonwakeupStatus)
hostIntfSetInterrupt(NANOHUB_INT_NONWAKEUP);
}
void nanohubPrefetchTx(uint32_t interrupt, uint32_t wakeup, uint32_t nonwakeup)
{
uint64_t state;
if (wakeup < atomicRead32bits(&mTxWakeCnt[0]))
wakeup = atomicRead32bits(&mTxWakeCnt[0]);
if (nonwakeup < atomicRead32bits(&mTxWakeCnt[1]))
nonwakeup = atomicRead32bits(&mTxWakeCnt[1]);
if (interrupt == HOSTINTF_MAX_INTERRUPTS && !hostIntfGetInterrupt(NANOHUB_INT_WAKEUP) && !hostIntfGetInterrupt(NANOHUB_INT_NONWAKEUP))
return;
atomicWriteByte(&mPrefetchActive, 1);
if (interrupt < HOSTINTF_MAX_INTERRUPTS)
hostIntfSetInterrupt(interrupt);
do {
if (atomicReadByte(&mTxCurrLength) == 0 && mTxNextLength > 0) {
memcpy(&mTxCurr, &mTxNext, mTxNextLength);
atomicWriteByte(&mTxCurrLength, mTxNextLength);
mTxNextLength = 0;
}
if (mTxNextLength == 0) {
atomicWriteByte(&mTxCurrLength, fillBuffer(&mTxCurr, atomicReadByte(&mTxCurrLength), &wakeup, &nonwakeup));
atomicWrite32bits(&mTxWakeCnt[0], wakeup);
atomicWrite32bits(&mTxWakeCnt[1], nonwakeup);
}
atomicWriteByte(&mPrefetchActive, 0);
if (atomicReadByte(&mPrefetchTx)) {
state = cpuIntsOff();
// interrupt occured during this call
// take care of it
hostIntfTxAck(&mTxCurr, atomicReadByte(&mTxCurrLength));
atomicWriteByte(&mPrefetchTx, 0);
atomicWriteByte(&mTxCurrLength, 0);
cpuIntsRestore(state);
updateInterrupts();
} else {
break;
}
} while (mTxNextLength > 0);
}
static void nanohubPrefetchTxDefer(void *cookie)
{
nanohubPrefetchTx(HOSTINTF_MAX_INTERRUPTS, 0, 0);
}
static uint32_t readEventFast(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
{
struct NanohubReadEventRequest *req = rx;
uint8_t ret = 0;
if (atomicReadByte(&mPrefetchActive)) {
atomicWriteByte(&mPrefetchTx, 1);
return NANOHUB_FAST_DONT_ACK;
} else {
if ((ret = atomicReadByte(&mTxCurrLength))) {
addDelta(&mTimeSync, req->apBootTime, timestamp);
memcpy(tx, &mTxCurr, ret);
atomicWriteByte(&mTxCurrLength, 0);
updateInterrupts();
osDefer(nanohubPrefetchTxDefer, NULL, true);
} else {
return NANOHUB_FAST_UNHANDLED_ACK;
}
}
return ret;
}
static uint32_t readEvent(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
{
struct NanohubReadEventRequest *req = rx;
uint8_t *buf = tx;
uint32_t length, wakeup, nonwakeup;
uint32_t totLength = 0;
addDelta(&mTimeSync, req->apBootTime, timestamp);
if ((totLength = atomicReadByte(&mTxCurrLength))) {
memcpy(tx, &mTxCurr, totLength);
atomicWriteByte(&mTxCurrLength, 0);
updateInterrupts();
return totLength;
}
wakeup = atomicRead32bits(&mTxWakeCnt[0]);
nonwakeup = atomicRead32bits(&mTxWakeCnt[1]);
if (mTxNextLength > 0) {
length = mTxNextLength;
memcpy(buf, &mTxNext, length);
totLength = length;
mTxNextLength = 0;
}
totLength = fillBuffer(buf, totLength, &wakeup, &nonwakeup);
atomicWrite32bits(&mTxWakeCnt[0], wakeup);
atomicWrite32bits(&mTxWakeCnt[1], nonwakeup);
if (totLength) {
updateInterrupts();
} else {
hostIntfClearInterrupt(NANOHUB_INT_WAKEUP);
hostIntfClearInterrupt(NANOHUB_INT_NONWAKEUP);
}
return totLength;
}
static bool forwardPacket(uint32_t event, void *data, size_t data_size,
void *hdr, size_t hdr_size, uint32_t tid)
{
bool res;
uint8_t *hostPacket = data;
uint8_t *packet = slabAllocatorAlloc(mEventSlab);
EventFreeF free = slabFree;
if (!packet) {
packet = heapAlloc(data_size + hdr_size);
free = heapFree;
}
if (!packet)
return false;
if (hdr && hdr_size)
memcpy(packet, hdr, hdr_size);
memcpy(packet + hdr_size, hostPacket, data_size);
if (tid) {
// send to specific TID
res = osEnqueuePrivateEvt(event, packet, free, tid);
if (!res)
free(packet);
} else {
// broadcast to all
res = osEnqueueEvtOrFree(event, packet, free);
}
return res;
}
static uint32_t writeEvent(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
{
struct NanohubWriteEventRequest *req = rx;
struct NanohubWriteEventResponse *resp = tx;
uint32_t tid;
uint32_t event = le32toh(req->evtType);
if (event == EVT_APP_FROM_HOST) {
// old version of HAL; message_type is not delivered to CHRE apps
struct HostMsgHdr *hostPacket = rx;
if (rx_len >= sizeof(struct HostMsgHdr) &&
rx_len == sizeof(struct HostMsgHdr) + hostPacket->len &&
osTidById(&hostPacket->appId, &tid)) {
resp->accepted = forwardPacket(event, hostPacket + 1, hostPacket->len,
&hostPacket->len, sizeof(hostPacket->len), tid);
} else {
resp->accepted = false;
}
} else if (event == EVT_APP_FROM_HOST_CHRE) {
// new version of HAL; full support for CHRE apps
struct HostMsgHdrChreV10 *hostPacketV10 = rx;
struct HostMsgHdrChre *hostPacket = rx;
if (rx_len >= sizeof(struct HostMsgHdrChre) &&
rx_len == sizeof(struct HostMsgHdrChre) + hostPacket->len &&
osTidById(&hostPacket->appId, &tid)) {
if (osAppChreVersion(tid) >= CHRE_API_VERSION_1_1) {
struct NanohubMsgChreHdr hdr = {
.size = hostPacket->len,
.endpoint = hostPacket->endpoint,
.appEvent = hostPacket->appEventId,
};
// CHRE app receives message in new format
resp->accepted = forwardPacket(event, hostPacket + 1, hostPacket->len,
&hdr, sizeof(hdr), tid);
} else if (osAppChreVersion(tid) == CHRE_API_VERSION_1_0) {
struct NanohubMsgChreHdrV10 hdr = {
.size = hostPacket->len,
.appEvent = hostPacket->appEventId,
};
// CHRE app receives message in new format
resp->accepted = forwardPacket(event, hostPacket + 1, hostPacket->len,
&hdr, sizeof(hdr), tid);
} else {
// legacy app receives message in old format
resp->accepted = forwardPacket(EVT_APP_FROM_HOST, hostPacket + 1, hostPacket->len,
&hostPacket->len, sizeof(hostPacket->len), tid);
}
} else if (rx_len >= sizeof(struct HostMsgHdrChreV10) &&
rx_len == sizeof(struct HostMsgHdrChreV10) + hostPacketV10->len &&
osTidById(&hostPacketV10->appId, &tid)) {
if (osAppChreVersion(tid) >= CHRE_API_VERSION_1_1) {
struct NanohubMsgChreHdr hdr = {
.size = hostPacketV10->len,
.endpoint = CHRE_HOST_ENDPOINT_UNSPECIFIED,
.appEvent = hostPacketV10->appEventId,
};
// CHRE app receives message in new format
resp->accepted = forwardPacket(event, hostPacketV10 + 1, hostPacketV10->len,
&hdr, sizeof(hdr), tid);
} else if (osAppChreVersion(tid) == CHRE_API_VERSION_1_0) {
struct NanohubMsgChreHdrV10 hdr = {
.size = hostPacketV10->len,
.appEvent = hostPacketV10->appEventId,
};
// CHRE app receives message in new format
resp->accepted = forwardPacket(event, hostPacketV10 + 1, hostPacketV10->len,
&hdr, sizeof(hdr), tid);
} else {
// legacy app receives message in old format
resp->accepted = forwardPacket(EVT_APP_FROM_HOST, hostPacketV10 + 1, hostPacketV10->len,
&hostPacketV10->len, sizeof(hostPacketV10->len), tid);
}
} else {
resp->accepted = false;
}
} else {
resp->accepted = forwardPacket(event,
req->evtData, rx_len - sizeof(req->evtType),
NULL, 0, 0);
}
return sizeof(*resp);
}
const static struct NanohubCommand mBuiltinCommands[] = {
NANOHUB_COMMAND(NANOHUB_REASON_GET_OS_HW_VERSIONS,
getOsHwVersion,
getOsHwVersion,
struct NanohubOsHwVersionsRequest,
struct NanohubOsHwVersionsRequest),
NANOHUB_COMMAND(NANOHUB_REASON_GET_APP_VERSIONS,
NULL,
getAppVersion,
struct NanohubAppVersionsRequest,
struct NanohubAppVersionsRequest),
NANOHUB_COMMAND(NANOHUB_REASON_QUERY_APP_INFO,
NULL,
queryAppInfo,
struct NanohubAppInfoRequest,
struct NanohubAppInfoRequest),
NANOHUB_COMMAND(NANOHUB_REASON_START_FIRMWARE_UPLOAD,
NULL,
startFirmwareUpload,
struct NanohubStartFirmwareUploadRequest,
struct NanohubStartFirmwareUploadRequest),
NANOHUB_COMMAND(NANOHUB_REASON_FIRMWARE_CHUNK,
NULL,
firmwareChunk,
__le32,
struct NanohubFirmwareChunkRequest),
NANOHUB_COMMAND(NANOHUB_REASON_FINISH_FIRMWARE_UPLOAD,
NULL,
finishFirmwareUpload,
struct NanohubFinishFirmwareUploadRequest,
struct NanohubFinishFirmwareUploadRequest),
NANOHUB_COMMAND(NANOHUB_REASON_GET_INTERRUPT,
getInterrupt,
getInterrupt,
struct { },
struct NanohubGetInterruptRequest),
NANOHUB_COMMAND(NANOHUB_REASON_MASK_INTERRUPT,
maskInterrupt,
maskInterrupt,
struct NanohubMaskInterruptRequest,
struct NanohubMaskInterruptRequest),
NANOHUB_COMMAND(NANOHUB_REASON_UNMASK_INTERRUPT,
unmaskInterrupt,
unmaskInterrupt,
struct NanohubUnmaskInterruptRequest,
struct NanohubUnmaskInterruptRequest),
NANOHUB_COMMAND(NANOHUB_REASON_READ_EVENT,
readEventFast,
readEvent,
struct NanohubReadEventRequest,
struct NanohubReadEventRequest),
NANOHUB_COMMAND(NANOHUB_REASON_WRITE_EVENT,
writeEvent,
writeEvent,
__le32,
struct NanohubWriteEventRequest),
};
const struct NanohubCommand *nanohubFindCommand(uint32_t packetReason)
{
uint32_t i;
for (i = 0; i < ARRAY_SIZE(mBuiltinCommands); i++) {
const struct NanohubCommand *cmd = &mBuiltinCommands[i];
if (cmd->reason == packetReason)
return cmd;
}
return NULL;
}
#ifdef LEGACY_HAL_ENABLED
static void halSendLegacyMgmtResponse(uint32_t cmd, uint32_t status)
{
struct NanohubHalLegacyMgmtTx *resp;
resp = heapAlloc(sizeof(*resp));
if (resp) {
resp->hdr = (struct NanohubHalLegacyHdr) {
.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
.len = sizeof(*resp) - sizeof(resp->hdr) + sizeof(resp->hdr.msg),
.msg = cmd,
};
resp->status = htole32(status);
osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree);
}
}
static void halLegacyExtAppsOn(void *rx, uint8_t rx_len)
{
struct NanohubHalLegacyMgmtRx *req = rx;
halSendLegacyMgmtResponse(NANOHUB_HAL_LEGACY_EXT_APPS_ON, osExtAppStartAppsByAppId(le64toh(unaligned_u64(&req->appId))));
}
static void halLegacyExtAppsOff(void *rx, uint8_t rx_len)
{
struct NanohubHalLegacyMgmtRx *req = rx;
halSendLegacyMgmtResponse(NANOHUB_HAL_LEGACY_EXT_APPS_OFF, osExtAppStopAppsByAppId(le64toh(unaligned_u64(&req->appId))));
}
static void halLegacyExtAppDelete(void *rx, uint8_t rx_len)
{
struct NanohubHalLegacyMgmtRx *req = rx;
halSendLegacyMgmtResponse(NANOHUB_HAL_LEGACY_EXT_APP_DELETE, osExtAppEraseAppsByAppId(le64toh(unaligned_u64(&req->appId))));
}
static void halLegacyQueryMemInfo(void *rx, uint8_t rx_len)
{
}
static void halLegacyQueryApps(void *rx, uint8_t rx_len)
{
struct NanohubHalLegacyQueryAppsRx *req = rx;
struct NanohubHalLegacyQueryAppsTx *resp;
struct NanohubHalLegacyHdr *hdr;
uint64_t appId;
uint32_t appVer, appSize;
if (osExtAppInfoByIndex(le32toh(req->idx), &appId, &appVer, &appSize)) {
resp = heapAlloc(sizeof(*resp));
if (resp) {
resp->hdr.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0);
resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalLegacyHdr) + 1;
resp->hdr.msg = NANOHUB_HAL_LEGACY_QUERY_APPS;
resp->appId = appId;
resp->version = appVer;
resp->flashUse = appSize;
resp->ramUse = 0;
osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree);
}
} else {
hdr = heapAlloc(sizeof(*hdr));
if (hdr) {
hdr->appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0);
hdr->len = 1;
hdr->msg = NANOHUB_HAL_LEGACY_QUERY_APPS;
osEnqueueEvtOrFree(EVT_APP_TO_HOST, hdr, heapFree);
}
}
}
static void halLegacyQueryRsaKeys(void *rx, uint8_t rx_len)
{
struct NanohubHalLegacyQueryRsaKeysRx *req = rx;
struct NanohubHalLegacyQueryRsaKeysTx *resp;
int len = 0;
const uint32_t *ptr;
uint32_t numKeys;
if (!(resp = heapAlloc(sizeof(*resp) + NANOHUB_RSA_KEY_CHUNK_LEN)))
return;
ptr = BL.blGetPubKeysInfo(&numKeys);
if (ptr && numKeys * RSA_BYTES > req->offset) {
len = numKeys * RSA_BYTES - req->offset;
if (len > NANOHUB_RSA_KEY_CHUNK_LEN)
len = NANOHUB_RSA_KEY_CHUNK_LEN;
memcpy(resp->data, (uint8_t *)ptr + req->offset, len);
}
resp->hdr.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0);
resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalLegacyHdr) + 1 + len;
resp->hdr.msg = NANOHUB_HAL_LEGACY_QUERY_RSA_KEYS;
osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree);
}
static void halLegacyStartUpload(void *rx, uint8_t rx_len)
{
struct NanohubHalLegacyStartUploadRx *req = rx;
struct NanohubStartFirmwareUploadRequest hwReq = {
.size = req->length
};
struct NanohubHalLegacyStartUploadTx *resp;
if (!(resp = heapAlloc(sizeof(*resp))))
return;
resp->hdr.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0);
resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalLegacyHdr) + 1;
resp->hdr.msg = NANOHUB_HAL_LEGACY_START_UPLOAD;
resp->success = doStartFirmwareUpload(&hwReq, true);
osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree);
}
static void halLegacyContUpload(void *rx, uint8_t rx_len)
{
uint32_t offset;
uint32_t reply;
uint8_t len;
struct NanohubHalLegacyContUploadRx *req = rx;
struct FirmwareWriteCookie *cookie;
if (!(cookie = heapAlloc(sizeof(*cookie))))
return;
cookie->evtType = EVT_APP_TO_HOST;
cookie->respLegacy.hdr = (struct NanohubHalLegacyHdr) {
.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
.len = sizeof(cookie->respLegacy) - sizeof(struct NanohubHalLegacyHdr) + 1,
.msg = NANOHUB_HAL_LEGACY_CONT_UPLOAD,
};
cookie->respLegacy.success = false;
if (!mDownloadState) {
reply = NANOHUB_FIRMWARE_CHUNK_REPLY_CANCEL_NO_RETRY;
} else {
offset = le32toh(req->offset);
len = rx_len - sizeof(req->offset);
reply = doFirmwareChunk(req->data, offset, len, cookie);
}
if (reply != NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED) {
osLog(LOG_ERROR, "%s: reply=%" PRIu32 "\n", __func__, reply);
osEnqueueEvtOrFree(EVT_APP_TO_HOST, &cookie->respLegacy, writeCookieFree);
}
}
static void halLegacyFinishUpload(void *rx, uint8_t rx_len)
{
struct NanohubHalLegacyFinishUploadTx *resp;
uint32_t reply;
if (!(resp = heapAlloc(sizeof(*resp))))
return;
resp->hdr.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0);
resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalLegacyHdr) + 1;
resp->hdr.msg = NANOHUB_HAL_LEGACY_FINISH_UPLOAD;
reply = doFinishFirmwareUpload(NULL, NULL);
osLog(LOG_INFO, "%s: reply=%" PRIu32 "\n", __func__, reply);
resp->success = (reply == NANOHUB_FIRMWARE_UPLOAD_SUCCESS);
osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree);
}
static void halLegacyReboot(void *rx, uint8_t rx_len)
{
BL.blReboot();
}
const static struct NanohubHalLegacyCommand mBuiltinHalLegacyCommands[] = {
NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_EXT_APPS_ON,
halLegacyExtAppsOn),
NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_EXT_APPS_OFF,
halLegacyExtAppsOff),
NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_EXT_APP_DELETE,
halLegacyExtAppDelete),
NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_QUERY_MEMINFO,
halLegacyQueryMemInfo),
NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_QUERY_APPS,
halLegacyQueryApps),
NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_QUERY_RSA_KEYS,
halLegacyQueryRsaKeys),
NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_START_UPLOAD,
halLegacyStartUpload),
NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_CONT_UPLOAD,
halLegacyContUpload),
NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_FINISH_UPLOAD,
halLegacyFinishUpload),
NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_REBOOT,
halLegacyReboot),
};
const struct NanohubHalLegacyCommand *nanohubHalLegacyFindCommand(uint8_t msg)
{
uint32_t i;
for (i = 0; i < ARRAY_SIZE(mBuiltinHalLegacyCommands); i++) {
const struct NanohubHalLegacyCommand *cmd = &mBuiltinHalLegacyCommands[i];
if (cmd->msg == msg)
return cmd;
}
return NULL;
}
#endif /* LEGACY_HAL_ENABLED */
static void halSendAppMgmtResponse(struct NanohubHalAppMgmtRx *req, uint32_t status, struct MgmtStatus stat, uint32_t transactionId)
{
struct NanohubHalAppMgmtTx *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),
.transactionId = transactionId,
};
resp->ret = (struct NanohubHalRet) {
.msg = NANOHUB_HAL_APP_MGMT,
.status = htole32(status),
};
resp->cmd = req->cmd;
resp->stat = stat;
osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
}
}
static void halAppMgmt(void *rx, uint8_t rx_len, uint32_t transactionId)
{
struct NanohubHalAppMgmtRx *req = rx;
struct MgmtStatus stat;
uint32_t ret;
switch (req->cmd) {
case NANOHUB_HAL_APP_MGMT_START:
stat.value= osExtAppStartAppsByAppId(le64toh(unaligned_u64(&req->appId)));
ret = stat.op > 0 ? 0 : -1;
break;
case NANOHUB_HAL_APP_MGMT_STOP:
stat.value = osExtAppStopAppsByAppId(le64toh(unaligned_u64(&req->appId)));
ret = stat.op > 0 ? 0 : -1;
break;
case NANOHUB_HAL_APP_MGMT_UNLOAD:
stat.value = osExtAppStopAppsByAppId(le64toh(unaligned_u64(&req->appId)));
ret = stat.op > 0 ? 0 : -1;
break;
case NANOHUB_HAL_APP_MGMT_DELETE:
stat.value = osExtAppEraseAppsByAppId(le64toh(unaligned_u64(&req->appId)));
ret = stat.erase > 0 ? 0 : -1;
break;
default:
return;
}
halSendAppMgmtResponse(req, ret, stat, transactionId);
}
static void deferHalSysMgmtErase(void *cookie)
{
struct NanohubHalSysMgmtTx *resp = cookie;
bool success = osEraseShared();
if (success)
resp->ret.status = htole32(0);
else
resp->ret.status = htole32(-1);
osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
}
static void halSysMgmt(void *rx, uint8_t rx_len, uint32_t transactionId)
{
struct NanohubHalSysMgmtRx *req = rx;
struct NanohubHalSysMgmtTx *resp;
uint32_t ret = 0;
if (!(resp = heapAlloc(sizeof(*resp))))
return;
resp->hdr = (struct NanohubHalHdr) {
.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
.len = sizeof(*resp) - sizeof(resp->hdr),
.transactionId = transactionId,
};
resp->ret = (struct NanohubHalRet) {
.msg = NANOHUB_HAL_SYS_MGMT,
};
resp->cmd = req->cmd;
switch (req->cmd) {
case NANOHUB_HAL_SYS_MGMT_ERASE:
ret = osExtAppStopAppsByAppId(APP_ID_ANY);
osLog(LOG_INFO, "%s: unloaded apps, ret=%08lx\n", __func__, ret);
// delay to make sure all apps are unloaded before erasing
if (osDefer(deferHalSysMgmtErase, resp, false) == false) {
resp->ret.status = htole32(-1);
osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
}
break;
case NANOHUB_HAL_SYS_MGMT_REBOOT:
BL.blReboot();
break;
default:
resp->ret.status = htole32(-1);
osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
}
}
static bool copyTLV64(uint8_t *buf, size_t *offset, size_t max_len, uint8_t tag, uint64_t val)
{
if (*offset + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint64_t) > max_len)
return false;
buf[(*offset)++] = tag;
buf[(*offset)++] = sizeof(uint64_t);
memcpy(&buf[*offset], &val, sizeof(uint64_t));
*offset += sizeof(uint64_t);
return true;
}
static bool copyTLV32(uint8_t *buf, size_t *offset, size_t max_len, uint8_t tag, uint32_t val)
{
if (*offset + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t) > max_len)
return false;
buf[(*offset)++] = tag;
buf[(*offset)++] = sizeof(uint32_t);
memcpy(&buf[*offset], &val, sizeof(uint32_t));
*offset += sizeof(uint32_t);
return true;
}
static bool copyTLV8(uint8_t *buf, size_t *offset, size_t max_len, uint8_t tag, uint8_t val)
{
if (*offset + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) > max_len)
return false;
buf[(*offset)++] = tag;
buf[(*offset)++] = sizeof(uint8_t);
memcpy(&buf[*offset], &val, sizeof(uint8_t));
*offset += sizeof(uint8_t);
return true;
}
static bool copyTLVEmpty(uint8_t *buf, size_t *offset, size_t max_len, uint8_t tag)
{
if (*offset + sizeof(uint8_t) + sizeof(uint8_t) > max_len)
return false;
buf[(*offset)++] = tag;
buf[(*offset)++] = 0;
return true;
}
static int processAppTags(const struct AppHdr *app, uint32_t crc, uint32_t size, uint8_t *data, uint8_t *tags, int cnt, bool req_tid)
{
int i;
size_t offset = 0;
const size_t max_len = HOST_HUB_CHRE_PACKET_MAX_LEN - sizeof(struct NanohubHalRet);
bool success = true;
uint32_t tid;
bool tid_valid = false;
struct Task *task;
if (app->hdr.magic != APP_HDR_MAGIC ||
app->hdr.fwVer != APP_HDR_VER_CUR ||
(app->hdr.fwFlags & FL_APP_HDR_APPLICATION) == 0 ||
app->hdr.payInfoType != LAYOUT_APP) {
return 0;
}
if (osTidById(&app->hdr.appId, &tid)) {
tid_valid = true;
task = osTaskFindByTid(tid);
if (task) {
if (task->app != app)
tid_valid = false;
} else
tid_valid = false;
}
if (!tid_valid && req_tid)
return 0;
for (i=0; i<cnt && success; i++) {
switch(tags[i]) {
case NANOHUB_HAL_APP_INFO_APPID:
success = copyTLV64(data, &offset, max_len, tags[i], app->hdr.appId);
break;
case NANOHUB_HAL_APP_INFO_CRC:
if (size)
success = copyTLV32(data, &offset, max_len, tags[i], crc);
else
success = copyTLVEmpty(data, &offset, max_len, tags[i]);
break;
case NANOHUB_HAL_APP_INFO_TID:
if (tid_valid)
success = copyTLV32(data, &offset, max_len, tags[i], tid);
else
success = copyTLVEmpty(data, &offset, max_len, tags[i]);
break;
case NANOHUB_HAL_APP_INFO_VERSION:
success = copyTLV32(data, &offset, max_len, tags[i], app->hdr.appVer);
break;
case NANOHUB_HAL_APP_INFO_ADDR:
success = copyTLV32(data, &offset, max_len, tags[i], (uint32_t)app);
break;
case NANOHUB_HAL_APP_INFO_SIZE:
if (size)
success = copyTLV32(data, &offset, max_len, tags[i], size);
else
success = copyTLVEmpty(data, &offset, max_len, tags[i]);
break;
case NANOHUB_HAL_APP_INFO_HEAP:
if (tid_valid)
success = copyTLV32(data, &offset, max_len, tags[i], heapGetTaskSize(tid));
else
success = copyTLVEmpty(data, &offset, max_len, tags[i]);
break;
case NANOHUB_HAL_APP_INFO_DATA:
success = copyTLV32(data, &offset, max_len, tags[i], app->sect.got_end - app->sect.data_start);
break;
case NANOHUB_HAL_APP_INFO_BSS:
success = copyTLV32(data, &offset, max_len, tags[i], app->sect.bss_end - app->sect.bss_start);
break;
case NANOHUB_HAL_APP_INFO_CHRE_MAJOR:
if (app->hdr.fwFlags & FL_APP_HDR_CHRE)
success = copyTLV8(data, &offset, max_len, tags[i],
(app->hdr.chreApiMajor == 0xFF && app->hdr.chreApiMinor == 0xFF) ? 0x01 :
app->hdr.chreApiMajor);
else
success = copyTLVEmpty(data, &offset, max_len, tags[i]);
break;
case NANOHUB_HAL_APP_INFO_CHRE_MINOR:
if (app->hdr.fwFlags & FL_APP_HDR_CHRE)
success = copyTLV8(data, &offset, max_len, tags[i],
(app->hdr.chreApiMajor == 0xFF && app->hdr.chreApiMinor == 0xFF) ? 0x00 :
app->hdr.chreApiMinor);
else
success = copyTLVEmpty(data, &offset, max_len, tags[i]);
break;
case NANOHUB_HAL_APP_INFO_END:
default:
success = false;
copyTLVEmpty(data, &offset, max_len, NANOHUB_HAL_APP_INFO_END);
break;
}
}
return offset;
}
static void halAppInfo(void *rx, uint8_t rx_len, uint32_t transactionId)
{
struct NanohubHalAppInfoRx *req = rx;
struct NanohubHalAppInfoTx *resp;
struct SegmentIterator it;
uint32_t state;
int ret, i;
uint32_t sharedSize, numApps;
const struct AppHdr *internal;
const uint8_t *shared;
if (!(resp = heapAlloc(sizeof(*resp))))
return;
resp->hdr = (struct NanohubHalHdr) {
.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
.len = sizeof(*resp) - sizeof(resp->hdr) - sizeof(resp->data),
.transactionId = transactionId,
};
resp->ret = (struct NanohubHalRet) {
.msg = NANOHUB_HAL_APP_INFO,
};
shared = platGetSharedAreaInfo(&sharedSize);
internal = platGetInternalAppList(&numApps);
if ((le32toh(req->addr) >= (uint32_t)shared && le32toh(req->addr) < (uint32_t)shared + sharedSize) ||
(le32toh(req->addr) < (uint32_t)shared &&
((uint32_t)shared < (uint32_t)internal ||
(numApps > 0 && le32toh(req->addr) > (uint32_t)(internal+numApps-1))))) {
osSegmentIteratorInit(&it);
while (osSegmentIteratorNext(&it)) {
state = osSegmentGetState(it.seg);
switch (state) {
case SEG_ST_EMPTY:
case SEG_ST_RESERVED:
osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
return;
case SEG_ST_ERASED:
case SEG_ST_VALID:
if (le32toh(req->addr) <= (uint32_t)osSegmentGetData(it.seg)) {
ret = processAppTags(osSegmentGetData(it.seg), osSegmentGetCrc(it.seg), osSegmentGetSize(it.seg), resp->data, req->tags, rx_len - 4, state == SEG_ST_ERASED);
if (ret > 0) {
resp->hdr.len += ret;
osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
return;
}
}
break;
}
}
} else {
for (i = 0; i < numApps; i++, internal++) {
if (le32toh(req->addr) <= (uint32_t)internal) {
ret = processAppTags(internal, 0, 0, resp->data, req->tags, rx_len - 4, false);
if (ret > 0) {
resp->hdr.len += ret;
osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
return;
}
}
}
}
osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
}
static void halSysInfo(void *rx, uint8_t rx_len, uint32_t transactionId)
{
extern uint8_t __code_start[];
extern uint8_t __code_end[];
extern uint8_t __text_end[];
extern uint8_t __ram_start[];
extern uint8_t __ram_end[];
struct NanohubHalSysInfoRx *req = rx;
struct NanohubHalSysInfoTx *resp;
int i;
size_t offset = 0;
const size_t max_len = HOST_HUB_CHRE_PACKET_MAX_LEN - sizeof(struct NanohubHalRet);
bool success = true;
int free, chunks, largest;
uint32_t shared_size;
free = heapGetFreeSize(&chunks, &largest);
if (!(resp = heapAlloc(sizeof(*resp))))
return;
resp->hdr = (struct NanohubHalHdr) {
.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
.len = sizeof(*resp) - sizeof(resp->hdr) - sizeof(resp->data),
.transactionId = transactionId,
};
resp->ret = (struct NanohubHalRet) {
.msg = NANOHUB_HAL_SYS_INFO,
};
for (i=0; i<rx_len && success; i++) {
switch(req->tags[i]) {
case NANOHUB_HAL_SYS_INFO_HEAP_FREE:
if (free >= 0)
success = copyTLV32(resp->data, &offset, max_len, req->tags[i], free);
else
success = copyTLVEmpty(resp->data, &offset, max_len, req->tags[i]);
break;
case NANOHUB_HAL_SYS_INFO_RAM_SIZE:
success = copyTLV32(resp->data, &offset, max_len, req->tags[i], __ram_end - __ram_start);
break;
case NANOHUB_HAL_SYS_INFO_EEDATA_SIZE:
success = copyTLV32(resp->data, &offset, max_len, req->tags[i], eeDataGetSize());
break;
case NANOHUB_HAL_SYS_INFO_EEDATA_FREE:
success = copyTLV32(resp->data, &offset, max_len, req->tags[i], eeDataGetFree());
break;
case NANOHUB_HAL_SYS_INFO_CODE_SIZE:
success = copyTLV32(resp->data, &offset, max_len, req->tags[i], __code_end - __code_start);
break;
case NANOHUB_HAL_SYS_INFO_CODE_FREE:
success = copyTLV32(resp->data, &offset, max_len, req->tags[i], __code_end - __text_end);
break;
case NANOHUB_HAL_SYS_INFO_SHARED_SIZE:
platGetSharedAreaInfo(&shared_size);
success = copyTLV32(resp->data, &offset, max_len, req->tags[i], shared_size);
break;
case NANOHUB_HAL_SYS_INFO_SHARED_FREE:
success = copyTLV32(resp->data, &offset, max_len, req->tags[i], osSegmentGetFree());
break;
case NANOHUB_HAL_SYS_INFO_END:
default:
success = false;
copyTLVEmpty(resp->data, &offset, max_len, NANOHUB_HAL_APP_INFO_END);
break;
}
}
resp->hdr.len += offset;
osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
}
static void halKeyInfo(void *rx, uint8_t rx_len, uint32_t transactionId)
{
struct NanohubHalKeyInfoRx *req = rx;
struct NanohubHalKeyInfoTx *resp;
const uint32_t *ptr;
uint32_t numKeys;
uint32_t dataLength;
if (!(resp = heapAlloc(sizeof(*resp))))
return;
ptr = BL.blGetPubKeysInfo(&numKeys);
resp->hdr = (struct NanohubHalHdr) {
.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
.len = sizeof(*resp) - sizeof(resp->hdr) - sizeof(resp->data),
.transactionId = transactionId,
};
resp->ret = (struct NanohubHalRet) {
.msg = NANOHUB_HAL_KEY_INFO,
};
resp->keyLength = 0;
if (ptr && req->keyNum < numKeys) {
if (req->dataOffset < RSA_BYTES) {
resp->keyLength = RSA_BYTES;
if (RSA_BYTES - req->dataOffset > NANOHUB_RSA_KEY_CHUNK_LEN)
dataLength = NANOHUB_RSA_KEY_CHUNK_LEN;
else
dataLength = RSA_BYTES - req->dataOffset;
memcpy(resp->data, (const uint8_t *)ptr + (req->keyNum * RSA_BYTES) + req->dataOffset, dataLength);
resp->hdr.len += dataLength;
}
}
osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
}
static void halStartUpload(void *rx, uint8_t rx_len, uint32_t transactionId)
{
struct NanohubHalStartUploadRx *req = rx;
struct NanohubStartFirmwareUploadRequest hwReq = {
.size = req->length
};
struct NanohubHalStartUploadTx *resp;
if (!(resp = heapAlloc(sizeof(*resp))))
return;
resp->hdr = (struct NanohubHalHdr) {
.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
.len = sizeof(*resp) - sizeof(resp->hdr),
.transactionId = transactionId,
};
resp->ret.msg = NANOHUB_HAL_START_UPLOAD;
if (doStartFirmwareUpload(&hwReq, false))
resp->ret.status = NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED;
else
resp->ret.status = NANOHUB_FIRMWARE_CHUNK_REPLY_NO_SPACE;
osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
}
static void halContUpload(void *rx, uint8_t rx_len, uint32_t transactionId)
{
uint32_t offset;
uint32_t reply;
uint8_t len;
struct NanohubHalContUploadRx *req = rx;
struct FirmwareWriteCookie *cookie;
if (!(cookie = heapAlloc(sizeof(*cookie))))
return;
cookie->evtType = EVT_APP_TO_HOST_CHRE;
cookie->resp.hdr = (struct NanohubHalHdr) {
.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
.len = sizeof(cookie->resp) - sizeof(cookie->resp.hdr),
.transactionId = transactionId,
};
cookie->resp.ret = (struct NanohubHalRet) {
.msg = NANOHUB_HAL_CONT_UPLOAD,
};
if (!mDownloadState) {
reply = NANOHUB_FIRMWARE_CHUNK_REPLY_CANCEL_NO_RETRY;
} else {
offset = le32toh(req->offset);
len = rx_len - sizeof(req->offset);
reply = doFirmwareChunk(req->data, offset, len, cookie);
}
if (reply != NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED) {
osLog(LOG_ERROR, "%s: reply=%" PRIu32 "\n", __func__, reply);
cookie->resp.ret.status = reply;
osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, &cookie->resp, writeCookieFree);
}
}
static void halFinishUpload(void *rx, uint8_t rx_len, uint32_t transactionId)
{
struct NanohubHalFinishUploadTx *resp;
uint32_t reply;
uint32_t addr = 0xFFFFFFFF;
uint32_t crc = 0xFFFFFFFF;
if (!(resp = heapAlloc(sizeof(*resp))))
return;
resp->hdr = (struct NanohubHalHdr) {
.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
.len = sizeof(*resp) - sizeof(resp->hdr),
.transactionId = transactionId,
};
reply = doFinishFirmwareUpload(&addr, &crc);
osLog(LOG_INFO, "%s: reply=%" PRIu32 "\n", __func__, reply);
resp->ret = (struct NanohubHalRet) {
.msg = NANOHUB_HAL_FINISH_UPLOAD,
.status = reply,
};
resp->addr = addr;
resp->crc = crc;
osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
}
const static struct NanohubHalCommand mBuiltinHalCommands[] = {
NANOHUB_HAL_COMMAND(NANOHUB_HAL_APP_MGMT,
halAppMgmt,
struct NanohubHalAppMgmtRx,
struct NanohubHalAppMgmtRx),
NANOHUB_HAL_COMMAND(NANOHUB_HAL_SYS_MGMT,
halSysMgmt,
struct NanohubHalSysMgmtRx,
struct NanohubHalSysMgmtRx),
NANOHUB_HAL_COMMAND(NANOHUB_HAL_APP_INFO,
halAppInfo,
__le32,
struct NanohubHalAppInfoRx),
NANOHUB_HAL_COMMAND(NANOHUB_HAL_SYS_INFO,
halSysInfo,
struct { },
struct NanohubHalSysInfoRx),
NANOHUB_HAL_COMMAND(NANOHUB_HAL_KEY_INFO,
halKeyInfo,
struct NanohubHalKeyInfoRx,
struct NanohubHalKeyInfoRx),
NANOHUB_HAL_COMMAND(NANOHUB_HAL_START_UPLOAD,
halStartUpload,
struct NanohubHalStartUploadRx,
struct NanohubHalStartUploadRx),
NANOHUB_HAL_COMMAND(NANOHUB_HAL_CONT_UPLOAD,
halContUpload,
__le32,
struct NanohubHalContUploadRx),
NANOHUB_HAL_COMMAND(NANOHUB_HAL_FINISH_UPLOAD,
halFinishUpload,
struct { },
struct { }),
};
const struct NanohubHalCommand *nanohubHalFindCommand(uint8_t msg)
{
uint32_t i;
for (i = 0; i < ARRAY_SIZE(mBuiltinHalCommands); i++) {
const struct NanohubHalCommand *cmd = &mBuiltinHalCommands[i];
if (cmd->msg == msg)
return cmd;
}
return NULL;
}
int64_t hostGetTimeDelta(void)
{
int64_t delta = getAvgDelta(&mTimeSync);
if (delta == INT64_MIN)
return 0ULL;
else
return delta;
}
uint64_t hostGetTime(void)
{
int64_t delta = getAvgDelta(&mTimeSync);
if (!delta || delta == INT64_MIN)
return 0ULL;
else
return sensorGetTime() + delta;
}
#if DEBUG_APHUB_TIME_SYNC
#define N_APHUB_SYNC_DATA 256
#define PRINT_DELAY 20000000 // unit ns, 20ms
struct ApHubSyncDebug {
uint64_t apFirst;
uint64_t hubFirst;
uint32_t apDelta[N_APHUB_SYNC_DATA]; // us
uint32_t hubDelta[N_APHUB_SYNC_DATA]; // us
int printIndex; //negative means not printing
int writeIndex;
uint32_t printTimer;
};
static struct ApHubSyncDebug mApHubSyncDebug;
static void syncDebugCallback(uint32_t timerId, void *data)
{
if (mApHubSyncDebug.printIndex >= mApHubSyncDebug.writeIndex ||
mApHubSyncDebug.printIndex >= N_APHUB_SYNC_DATA) {
timTimerCancel(mApHubSyncDebug.printTimer);
osLog(LOG_DEBUG, "APHUB Done printing %d items", mApHubSyncDebug.printIndex);
mApHubSyncDebug.writeIndex = 0;
mApHubSyncDebug.printIndex = -1;
mApHubSyncDebug.printTimer = 0;
} else {
if (mApHubSyncDebug.printIndex == 0) {
osLog(LOG_DEBUG, "APHUB init %" PRIu64 " %" PRIu64,
mApHubSyncDebug.apFirst,
mApHubSyncDebug.hubFirst);
}
osLog(LOG_DEBUG, "APHUB %d %" PRIu32 " %" PRIu32,
mApHubSyncDebug.printIndex,
mApHubSyncDebug.apDelta[mApHubSyncDebug.printIndex],
mApHubSyncDebug.hubDelta[mApHubSyncDebug.printIndex]);
mApHubSyncDebug.printIndex++;
}
}
static void syncDebugTriggerPrint()
{
if (mApHubSyncDebug.printTimer) {
//printing already going
return;
}
mApHubSyncDebug.printIndex = 0;
syncDebugCallback(0, NULL);
if (!(mApHubSyncDebug.printTimer =
timTimerSet(PRINT_DELAY, 0, 50, syncDebugCallback, NULL, false /*oneShot*/))) {
osLog(LOG_WARN, "Cannot get timer for printing");
mApHubSyncDebug.writeIndex = 0; // discard all data
mApHubSyncDebug.printIndex = -1; // not printing
}
}
static void syncDebugAdd(uint64_t ap, uint64_t hub)
{
if (mApHubSyncDebug.writeIndex >= N_APHUB_SYNC_DATA) {
//full
syncDebugTriggerPrint();
return;
}
if (mApHubSyncDebug.writeIndex == 0) {
mApHubSyncDebug.apFirst = ap;
mApHubSyncDebug.hubFirst = hub;
}
// convert ns to us
mApHubSyncDebug.apDelta[mApHubSyncDebug.writeIndex] =
(uint32_t) U64_DIV_BY_CONST_U16((ap - mApHubSyncDebug.apFirst), 1000u);
mApHubSyncDebug.hubDelta[mApHubSyncDebug.writeIndex] =
(uint32_t) U64_DIV_BY_CONST_U16((hub - mApHubSyncDebug.hubFirst), 1000u);
++mApHubSyncDebug.writeIndex;
}
#endif