普通文本  |  899行  |  30.46 KB

/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "chre/platform/platform_sensor.h"

#include "sns_std_sensor.pb.h"
#include "stringl.h"

#include <cmath>

#include "chre_api/chre/sensor.h"
#include "chre/core/event_loop_manager.h"
#include "chre/core/sensor.h"
#include "chre/platform/assert.h"
#include "chre/platform/fatal_error.h"
#include "chre/platform/log.h"
#include "chre/platform/shared/platform_sensor_util.h"
#include "chre/platform/slpi/power_control_util.h"
#include "chre/platform/slpi/see/see_client.h"
#include "chre/platform/slpi/see/see_helper.h"
#include "chre/platform/system_time.h"

#ifdef CHREX_SENSOR_SUPPORT
#include "chre/extensions/platform/slpi/see/vendor_data_types.h"
#endif  // CHREX_SENSOR_SUPPORT

#ifdef CHRE_VARIANT_SUPPLIES_SEE_SENSORS_LIST
#include "see_sensors.h"
#endif  // CHRE_VARIANT_SUPPLIES_SEE_SENSORS_LIST

#ifndef CHRE_SEE_NUM_TEMP_SENSORS
// There are usually more than one 'sensor_temperature' sensors in SEE.
// Define this in the variant-specific makefile to avoid missing sensors in
// sensor discovery.
#error "CHRE_SEE_NUM_TEMP_SENSORS is not defined"
#endif

namespace chre {
namespace {

#ifdef CHRE_SLPI_UIMG_ENABLED
#ifndef CHREX_SENSOR_SUPPORT
// The current implementation uses vendor sensor type 3 to remap into accel,
// with requests made through QMI instead of QSockets, as SEE does not support
// micro-image batching in QCM.
#error "CHRE extensions are required for micro-image SEE support"
#endif  // CHREX_SENSOR_SUPPORT

bool isBigImageSensorType(SensorType sensorType) {
  return (sensorType == SensorType::VendorType3       // accel
          || sensorType == SensorType::VendorType6    // uncal accel
          || sensorType == SensorType::VendorType7    // uncal gyro
          || sensorType == SensorType::VendorType8);  // uncal mag
}

/**
 * Obtains the big-image sensor type given the specified data type and whether
 * the sensor is runtime-calibrated or not.
 */
SensorType getBigImageSensorTypeFromDataType(const char *dataType,
                                             bool calibrated) {
  SensorType sensorType = SensorType::Unknown;
  if (strcmp(dataType, "accel") == 0) {
    if (calibrated) {
      sensorType = SensorType::VendorType3;
    } else {
      sensorType = SensorType::VendorType6;
    }
  } else if (strcmp(dataType, "gyro") == 0 && !calibrated) {
    sensorType = SensorType::VendorType7;
  } else if (strcmp(dataType, "mag") == 0 && !calibrated) {
    sensorType = SensorType::VendorType8;
  }
  return sensorType;
}

/**
 * Obtains the micro-image sensor type given the specified sensor type.
 *
 * @param sensorType The sensor type to convert from.
 * @return The associated micro-image sensor type, or the input sensor type
 *     if not associated with one
 */
SensorType getUimgSensorType(SensorType sensorType) {
  switch (sensorType) {
    case SensorType::VendorType3:
      return SensorType::Accelerometer;
    case SensorType::VendorType6:
      return SensorType::UncalibratedAccelerometer;
    case SensorType::VendorType7:
      return SensorType::UncalibratedGyroscope;
    case SensorType::VendorType8:
      return SensorType::UncalibratedGeomagneticField;
    default:
      return sensorType;
  }
}
#endif  // CHRE_SLPI_UIMG_ENABLED

//! A class that implements SeeHelperCallbackInterface.
class SeeHelperCallback : public SeeHelperCallbackInterface {
  void onSamplingStatusUpdate(
      UniquePtr<SeeHelperCallbackInterface::SamplingStatusData>&& status)
      override;

  void onSensorDataEvent(
      SensorType sensorType, UniquePtr<uint8_t>&& eventData) override;

  void onHostWakeSuspendEvent(bool awake) override;

  void onSensorBiasEvent(UniquePtr<struct chreSensorThreeAxisData>&& biasData)
      override;

  void onFlushCompleteEvent(SensorType sensorType) override;
};

//! A struct to facilitate sensor discovery
struct SuidAttr {
  sns_std_suid suid;
  SeeAttributes attr;
};

#ifndef CHRE_VARIANT_SUPPLIES_SEE_SENSORS_LIST

//! The list of SEE platform sensor data types that CHRE intends to support.
//! The standardized strings are defined in sns_xxx.proto.
const char *kSeeDataTypes[] = {
  "accel",
  "gyro",
  "mag",
  "pressure",
  "ambient_light",
  "proximity",
  "motion_detect",
  "stationary_detect",
};

#endif  // CHRE_VARIANT_SUPPLIES_SEE_SENSORS_LIST

void handleMissingSensor() {
  // Try rebooting if a sensor is missing, which might help recover from a
  // transient failure/race condition at startup. But to avoid endless crashes,
  // only do this within the first 45 seconds after boot - we rely on knowledge
  // that getMonotonicTime() maps into QTimer here, and QTimer only resets when
  // the entire system is rebooted (it continues increasing after SLPI SSR).
#ifndef CHRE_LOG_ONLY_NO_SENSOR
  if (SystemTime::getMonotonicTime() < Seconds(45)) {
    FATAL_ERROR("Missing required sensor(s)");
  } else
#endif
  {
    LOGE("Missing required sensor(s)");
  }
}

/**
 * Obtains the sensor type given the specified data type and whether the sensor
 * is runtime-calibrated or not.
 */
SensorType getSensorTypeFromDataType(const char *dataType, bool calibrated) {
  SensorType sensorType;
  if (strcmp(dataType, "accel") == 0) {
    if (calibrated) {
      sensorType = SensorType::Accelerometer;
    } else {
      sensorType = SensorType::UncalibratedAccelerometer;
    }
  } else if (strcmp(dataType, "gyro") == 0) {
    if (calibrated) {
      sensorType = SensorType::Gyroscope;
    } else {
      sensorType = SensorType::UncalibratedGyroscope;
    }
  } else if (strcmp(dataType, "mag") == 0) {
    if (calibrated) {
      sensorType = SensorType::GeomagneticField;
    } else {
      sensorType = SensorType::UncalibratedGeomagneticField;
    }
  } else if (strcmp(dataType, "pressure") == 0) {
    sensorType = SensorType::Pressure;
  } else if (strcmp(dataType, "ambient_light") == 0) {
    sensorType = SensorType::Light;
  } else if (strcmp(dataType, "proximity") == 0) {
    sensorType = SensorType::Proximity;
  } else if (strcmp(dataType, "motion_detect") == 0) {
    sensorType = SensorType::InstantMotion;
  } else if (strcmp(dataType, "stationary_detect") == 0) {
    sensorType = SensorType::StationaryDetect;
  } else if (strcmp(dataType, "step_detect") == 0) {
    sensorType = SensorType::StepDetect;
#ifdef CHREX_SENSOR_SUPPORT
  } else if (strcmp(dataType, kVendorDataTypes[0]) == 0) {
    sensorType = SensorType::VendorType0;
#endif  // CHREX_SENSOR_SUPPORT
  } else {
    sensorType = SensorType::Unknown;
  }
  return sensorType;
}

void seeSensorDataEventFree(uint16_t eventType, void *eventData) {
  memoryFree(eventData);

  // Remove all requests if it's a one-shot sensor and only after data has been
  // delivered to all clients.
  SensorType sensorType = getSensorTypeForSampleEventType(eventType);
  if (sensorTypeIsOneShot(sensorType)) {
    EventLoopManagerSingleton::get()->getSensorRequestManager()
        .removeAllRequests(sensorType);
  }
}

/**
 * Posts a CHRE_EVENT_SENSOR_SAMPLING_CHANGE event to the specified Nanoapp.
 *
 * @param instaceId The instance ID of the nanoapp with an open request.
 * @param sensorHandle The handle of the sensor.
 * @param status A reference of the sampling status to be posted.
 */
void postSamplingStatusEvent(uint32_t instanceId, uint32_t sensorHandle,
                             const struct chreSensorSamplingStatus& status) {
  auto *event = memoryAlloc<struct chreSensorSamplingStatusEvent>();
  if (event == nullptr) {
    LOG_OOM();
  } else {
    event->sensorHandle = sensorHandle;
    event->status = status;

    EventLoopManagerSingleton::get()->getEventLoop().postEventOrFree(
        CHRE_EVENT_SENSOR_SAMPLING_CHANGE, event, freeEventDataCallback,
        kSystemInstanceId, instanceId);
  }
}

/**
 * Helper function to post a bias event given the bias data.
 *
 * @param sensorType The sensor type to post the event for.
 * @param bias The bias data.
 */
void postSensorBiasEvent(SensorType sensorType,
                         const chreSensorThreeAxisData& bias) {
  uint16_t eventType;
  if (getSensorBiasEventType(sensorType, &eventType)) {
    auto *event = memoryAlloc<struct chreSensorThreeAxisData>();
    if (event == nullptr) {
      LOG_OOM();
    } else {
      *event = bias;
      event->header.sensorHandle = getSensorHandleFromSensorType(sensorType);
      EventLoopManagerSingleton::get()->getEventLoop().postEventOrFree(
          eventType, event, freeEventDataCallback);
    }
  }
}

/**
 * Updates the sampling status.
 */
void updateSamplingStatus(
    const SeeHelperCallbackInterface::SamplingStatusData& update) {
  Sensor *sensor = EventLoopManagerSingleton::get()->getSensorRequestManager()
      .getSensor(update.sensorType);
  struct chreSensorSamplingStatus prevStatus;

  if (sensor != nullptr && !sensorTypeIsOneShot(update.sensorType)
      && sensor->getSamplingStatus(&prevStatus)) {
    struct chreSensorSamplingStatus newStatus = prevStatus;

    if (update.enabledValid) {
      newStatus.enabled = update.status.enabled;
    }
    if (update.intervalValid) {
      newStatus.interval = update.status.interval;
    }
    if (update.latencyValid) {
      newStatus.latency = update.status.latency;
    }

    if (newStatus.enabled != prevStatus.enabled ||
        (newStatus.enabled && (newStatus.interval != prevStatus.interval
                               || newStatus.latency != prevStatus.latency))) {
      sensor->setSamplingStatus(newStatus);

      // Only post to Nanoapps with an open request.
      uint32_t sensorHandle = getSensorHandleFromSensorType(update.sensorType);
      const DynamicVector<SensorRequest>& requests =
          EventLoopManagerSingleton::get()->getSensorRequestManager()
          .getRequests(update.sensorType);
      for (const auto& req : requests) {
        postSamplingStatusEvent(req.getInstanceId(), sensorHandle, newStatus);
      }
    }
  }
}

void SeeHelperCallback::onSamplingStatusUpdate(
    UniquePtr<SeeHelperCallbackInterface::SamplingStatusData>&& status) {
  auto callback = [](uint16_t /* type */, void *data) {
    auto cbData = UniquePtr<SeeHelperCallbackInterface::SamplingStatusData>(
        static_cast<SeeHelperCallbackInterface::SamplingStatusData *>(data));
    updateSamplingStatus(*cbData);
  };

  // Schedule a deferred callback to handle sensor status change in the main
  // thread.
  EventLoopManagerSingleton::get()->deferCallback(
      SystemCallbackType::SensorStatusUpdate, status.release(), callback);
}

void SeeHelperCallback::onSensorDataEvent(
    SensorType sensorType, UniquePtr<uint8_t>&& eventData) {
  // Schedule a deferred callback to update on-change sensor's last event in
  // the main thread.
  if (sensorTypeIsOnChange(sensorType)) {
    updateLastEvent(sensorType, eventData.get());
  }

  uint16_t eventType = getSampleEventTypeForSensorType(sensorType);
  EventLoopManagerSingleton::get()->getEventLoop().postEventOrFree(
      eventType, eventData.get(), seeSensorDataEventFree);
  eventData.release();
}

void SeeHelperCallback::onHostWakeSuspendEvent(bool awake) {
  if (EventLoopManagerSingleton::isInitialized()) {
    EventLoopManagerSingleton::get()->getEventLoop()
        .getPowerControlManager().onHostWakeSuspendEvent(awake);
  }
}

void SeeHelperCallback::onSensorBiasEvent(
    UniquePtr<struct chreSensorThreeAxisData>&& biasData) {
  SensorType sensorType = getSensorTypeFromSensorHandle(
      biasData->header.sensorHandle);

  uint16_t eventType;
  if (!sensorTypeIsCalibrated(sensorType) ||
      !getSensorBiasEventType(sensorType, &eventType)) {
    LOGE("Received bias event for unsupported sensor type %" PRIu8, sensorType);
  } else {
    // Posts a newly allocated event for the uncalibrated type
    postSensorBiasEvent(toUncalibratedSensorType(sensorType), *biasData.get());

    EventLoopManagerSingleton::get()->getEventLoop().postEventOrFree(
        eventType, biasData.release(), freeEventDataCallback);
  }
}

void SeeHelperCallback::onFlushCompleteEvent(SensorType sensorType) {
  if (EventLoopManagerSingleton::isInitialized()) {
    EventLoopManagerSingleton::get()->getSensorRequestManager()
        .handleFlushCompleteEvent(CHRE_ERROR_NONE, sensorType);
  }
}

/**
 * Allocates memory and specifies the memory size for an on-change sensor to
 * store its last data event.
 *
 * @param sensorType The sensorType of this sensor.
 * @param eventSize A non-null pointer to indicate the memory size allocated.
 * @return Pointer to the memory allocated.
 */
ChreSensorData *allocateLastEvent(SensorType sensorType, size_t *eventSize) {
  CHRE_ASSERT(eventSize);

  *eventSize = 0;
  ChreSensorData *event = nullptr;
  if (sensorTypeIsOnChange(sensorType)) {
    SensorSampleType sampleType = getSensorSampleTypeFromSensorType(sensorType);
    switch (sampleType) {
      case SensorSampleType::ThreeAxis:
        *eventSize = sizeof(chreSensorThreeAxisData);
        break;
      case SensorSampleType::Float:
        *eventSize = sizeof(chreSensorFloatData);
        break;
      case SensorSampleType::Byte:
        *eventSize = sizeof(chreSensorByteData);
        break;
      case SensorSampleType::Occurrence:
        *eventSize = sizeof(chreSensorOccurrenceData);
        break;
      default:
        CHRE_ASSERT_LOG(false, "Unhandled sample type");
        break;
    }

    event = static_cast<ChreSensorData *>(memoryAlloc(*eventSize));
    if (event == nullptr) {
      *eventSize = 0;
      FATAL_ERROR("Failed to allocate last event memory for SensorType %" PRIu8,
                  static_cast<uint8_t>(sensorType));
    }
  }
  return event;
}

/**
 * Constructs and initializes a sensor, and adds it to the sensor list.
 *
 * @param seeHelper SeeHelper instance to register sensor with
 * @param suid The SUID of the sensor as provided by SEE.
 * @param sensorType The sensor type of the sensor.
 * @param calibrated Whether the sensor is runtime-calibrated or not.
 * @param attr A reference to SeeAttrbutes.
 * @param sensor The sensor list.
 */
void addSensor(SeeHelper& seeHelper, SensorType sensorType,
               const sns_std_suid& suid, const SeeAttributes& attr,
               DynamicVector<Sensor> *sensors) {
  // Concatenate vendor and name with a space in between.
  char sensorName[kSensorNameMaxLen];
  strlcpy(sensorName, attr.vendor, sizeof(sensorName));
  strlcat(sensorName, " ", sizeof(sensorName));
  strlcat(sensorName, attr.name, sizeof(sensorName));

  // Override one-shot sensor's minInterval to default
  uint64_t minInterval = sensorTypeIsOneShot(sensorType) ?
      CHRE_SENSOR_INTERVAL_DEFAULT : static_cast<uint64_t>(
          ceilf(Seconds(1).toRawNanoseconds() / attr.maxSampleRate));

  // Allocates memory for on-change sensor's last event.
  size_t lastEventSize;
  ChreSensorData *lastEvent = allocateLastEvent(sensorType, &lastEventSize);

  // Constructs and initializes PlatformSensorBase.
  Sensor sensor;
  sensor.initBase(sensorType, minInterval, sensorName, lastEvent,
                  lastEventSize, attr.passiveRequest);

  if (!sensors->push_back(std::move(sensor))) {
    FATAL_ERROR("Failed to allocate new sensor: out of memory");
  }

  // Resample big image sensors to reduce system load during sw flush.
#ifdef CHRE_SLPI_UIMG_ENABLED
  bool resample = isBigImageSensorType(sensorType);
#else
  bool resample = false;
#endif
  bool prevRegistered;
  bool registered = seeHelper.registerSensor(
      sensorType, suid, resample, &prevRegistered);
  if (!registered && prevRegistered) {
    LOGW("SUID has been previously registered");
  } else if (!registered) {
    FATAL_ERROR("Failed to register SUID/SensorType mapping.");
  }
}

/**
 * Compare SEE reported stream type attribute to the expected one. Some SEE
 * sensors may support more than one stream type.
 */
bool isStreamTypeCorrect(SensorType sensorType, uint8_t streamType) {
  bool success = true;
  if ((sensorTypeIsContinuous(sensorType)
       && streamType != SNS_STD_SENSOR_STREAM_TYPE_STREAMING)
      || (sensorTypeIsOnChange(sensorType)
          && streamType != SNS_STD_SENSOR_STREAM_TYPE_ON_CHANGE)
      || (sensorTypeIsOneShot(sensorType)
          && streamType != SNS_STD_SENSOR_STREAM_TYPE_SINGLE_OUTPUT)) {
    success = false;
    LOGW("Inconsistent sensor type %" PRIu8 " and stream type %" PRIu8,
         static_cast<uint8_t>(sensorType), streamType);
  }
  return success;
}

/**
 * Obtains the list of SUIDs and their attributes that support the specified
 * data type.
 */
bool getSuidAndAttrs(SeeHelper& seeHelper, const char *dataType,
                     DynamicVector<SuidAttr> *suidAttrs, uint8_t minNumSuids) {
  DynamicVector<sns_std_suid> suids;
  bool success = seeHelper.findSuidSync(dataType, &suids, minNumSuids);
  if (!success) {
    LOGE("Failed to find sensor '%s'", dataType);
  } else {
    LOGD("Num of SUIDs found for '%s': %zu", dataType, suids.size());

    for (const auto& suid : suids) {
      SeeAttributes attr;
      if (!seeHelper.getAttributesSync(suid, &attr)) {
        success = false;
        LOGE("Failed to get attributes of SUID 0x%" PRIx64 " %" PRIx64,
             suid.suid_high, suid.suid_low);
      } else {
        LOGI("%s %s, hw id %" PRId64 ", max ODR %f Hz, stream type %" PRIu8
             " passive %d",
             attr.vendor, attr.name, attr.hwId, attr.maxSampleRate,
             attr.streamType, attr.passiveRequest);
        SuidAttr sensor = {
          .suid = suid,
          .attr = attr,
        };
        if (!suidAttrs->push_back(sensor)) {
          success = false;
          LOG_OOM();
        }
      }
    }
  }
  return success;
}

//! Check whether two sensors with the specified attrtibutes belong to the same
//! sensor hardware module.
bool sensorHwMatch(const SeeAttributes& attr0, const SeeAttributes& attr1) {
  // When HW ID is absent, it's default to 0 and won't be a factor.
  return ((strncmp(attr0.vendor, attr1.vendor, kSeeAttrStrValLen) == 0)
          && (strncmp(attr0.name, attr1.name, kSeeAttrStrValLen) == 0)
          && (attr0.hwId == attr1.hwId));
}

/**
 * Looks up SUID(s) associated with a given sensor data type string and sensor
 * type enum, registers them with SeeHelper, and adds a Sensor instance to the
 * supplied vector for use in CHRE. When given an uncalibrated sensor type, will
 * also look for and add the calibrated sensor type.
 *
 * @param seeHelper SeeHelper instance to use for lookup/registration
 * @param temperatureSensors List of previously discovered temperature sensor
 *        info to use for adding temp sensors associated with this sensor type
 * @param dataType SEE data type string
 * @param sensorType CHRE sensor type enum associated with dataType
 * @param skipAdditionalTypes if true, don't attempt to add
 *        calibrated/temperature sensor types associated with this sensorType
 * @param sensors Vector to append found sensor(s) to
 */
void findAndAddSensorsForType(
    SeeHelper& seeHelper, const DynamicVector<SuidAttr>& temperatureSensors,
    const char *dataType, SensorType sensorType, bool skipAdditionalTypes,
    DynamicVector<Sensor> *sensors) {
  DynamicVector<SuidAttr> primarySensors;
  if (!getSuidAndAttrs(seeHelper, dataType, &primarySensors,
                       1 /* minNumSuids */)) {
    handleMissingSensor();
  }

  for (const auto& primarySensor : primarySensors) {
    sns_std_suid suid = primarySensor.suid;
    SeeAttributes attr = primarySensor.attr;

    // Some sensors support both continuous and on-change streams.
    // If there are more than one SUIDs that support the data type,
    // choose the first one that has the expected stream type.
    if (isStreamTypeCorrect(sensorType, attr.streamType)) {
      addSensor(seeHelper, sensorType, suid, attr, sensors);

      if (!skipAdditionalTypes) {
        // Check if this sensor has a runtime-calibrated version.
        SensorType calibratedType = getSensorTypeFromDataType(
            dataType, true /* calibrated */);
        if (calibratedType != sensorType) {
          addSensor(seeHelper, calibratedType, suid, attr, sensors);
        }

        // Check if this sensor has a secondary temperature sensor.
        SensorType temperatureType = getTempSensorType(sensorType);
        if (temperatureType != SensorType::Unknown) {
          bool tempFound = false;
          for (const auto& tempSensor : temperatureSensors) {
            sns_std_suid tempSuid = tempSensor.suid;
            SeeAttributes tempAttr = tempSensor.attr;

            if (sensorHwMatch(attr, tempAttr)) {
              LOGD("Found matching temperature sensor type");
              tempFound = true;
              addSensor(seeHelper, temperatureType, tempSuid, tempAttr,
                        sensors);
              break;
            }
          }
          if (!tempFound) {
            LOGW("Temperature sensor type %" PRIu8 " not found!",
                 static_cast<uint8_t>(temperatureType));
          }
        }
      }
      break;
    }
  }
}

#ifdef CHRE_SLPI_UIMG_ENABLED
/**
 * Registers alternate sensor(s) to be used separately by big image nanoapps.
 */
void getBigImageSensors(DynamicVector<Sensor> *sensors) {
  CHRE_ASSERT(sensors);

  // Currently, just adding calibrated accel and uncal accel/gyro/mag as they
  // are the ones we know that big image nanoapps will need at a different
  // batching rate compared to uimg.
  const char *kBigImageDataTypes[] = {
    "accel",
    "gyro",
    "mag",
  };

  SeeHelper& seeHelper = *getBigImageSeeHelper();
  DynamicVector<SuidAttr> nullTemperatureSensorList;

  for (size_t i = 0; i < ARRAY_SIZE(kBigImageDataTypes); i++) {
    const char *dataType = kBigImageDataTypes[i];
    // Loop through potential cal/uncal sensors.
    for (size_t j = 0; j < 2; j++) {
      SensorType sensorType = getBigImageSensorTypeFromDataType(
          dataType, (j == 0) /* calibrated */);
      if (sensorType != SensorType::Unknown) {
        findAndAddSensorsForType(
            seeHelper, nullTemperatureSensorList, dataType, sensorType,
            true /* skipAdditionalTypes */, sensors);
      }
    }
  }
}
#endif  // CHRE_SLPI_UIMG_ENABLED

/**
 * Helper function to retrieve the SeeHelper for a given sensor type.
 * @param sensorType the sensor type
 * @return the appropriate (bimg or uimg) SeeHelper
 */
SeeHelper *getSeeHelperForSensorType(SensorType sensorType) {
  SeeHelper *seeHelper = getSeeHelper();
#ifdef CHRE_SLPI_UIMG_ENABLED
  if (isBigImageSensorType(sensorType)) {
    seeHelper = getBigImageSeeHelper();
    slpiForceBigImage();
  }
#endif

  return seeHelper;
}


}  // anonymous namespace

PlatformSensor::~PlatformSensor() {
  if (mLastEvent != nullptr) {
    LOGD("Releasing lastEvent: sensor %s, size %zu",
         getSensorTypeName(getSensorType()), mLastEventSize);
    memoryFree(mLastEvent);
  }
}

void PlatformSensor::init() {
  SeeHelperSingleton::init();

  static SeeHelperCallback seeHelperCallback;
  if (!getSeeHelper()->init(&seeHelperCallback)) {
    FATAL_ERROR("Failed to initialize SEE helper");
  }

#ifdef CHRE_SLPI_UIMG_ENABLED
  BigImageSeeHelperSingleton::init(getSeeHelper()->getCalHelper());
  if (!getBigImageSeeHelper()->init(&seeHelperCallback, kDefaultSeeWaitTimeout,
                                    true /* skipDefaultSensorInit */)) {
    FATAL_ERROR("Failed to init bimg SEE helper");
  }
#endif  // CHRE_SLPI_UIMG_ENABLED
}

void PlatformSensor::deinit() {
#ifdef CHRE_SLPI_UIMG_ENABLED
  BigImageSeeHelperSingleton::deinit();
#endif

  SeeHelperSingleton::deinit();
}

bool PlatformSensor::getSensors(DynamicVector<Sensor> *sensors) {
  CHRE_ASSERT(sensors);

  SeeHelper& seeHelper = *getSeeHelper();
  DynamicVector<SuidAttr> tempSensors;
  if (!getSuidAndAttrs(seeHelper, "sensor_temperature", &tempSensors,
                       CHRE_SEE_NUM_TEMP_SENSORS)) {
    handleMissingSensor();
  }

#ifndef CHREX_SENSOR_SUPPORT
  const char *kVendorDataTypes[] = {};
#endif  // CHREX_SENSOR_SUPPORT
  constexpr size_t kNumSeeTypes = ARRAY_SIZE(kSeeDataTypes);
  constexpr size_t kNumVendorTypes = ARRAY_SIZE(kVendorDataTypes);
  for (size_t i = 0; i < kNumSeeTypes + kNumVendorTypes; i++) {
    const char *dataType = (i < kNumSeeTypes)
        ? kSeeDataTypes[i] : kVendorDataTypes[i - kNumSeeTypes];

    SensorType sensorType = getSensorTypeFromDataType(
        dataType, false /* calibrated */);
    if (sensorType == SensorType::Unknown) {
      LOGE("Unknown sensor type found for '%s'", dataType);
      continue;
    }

    findAndAddSensorsForType(seeHelper, tempSensors, dataType, sensorType,
                             false /* skipAdditionalTypes */, sensors);
  }

#ifdef CHRE_SLPI_UIMG_ENABLED
  getBigImageSensors(sensors);
#endif

  return true;
}

bool PlatformSensor::applyRequest(const SensorRequest& request) {
  SeeSensorRequest req = {
    .sensorType = getSensorType(),
    .enable = (request.getMode() != SensorMode::Off),
    .passive = sensorModeIsPassive(request.getMode()),
    .samplingRateHz = static_cast<float>(
        kOneSecondInNanoseconds / request.getInterval().toRawNanoseconds()),
    // Override batch period to 0 for non-continuous sensors to ensure one
    // sample per batch.
    .batchPeriodUs = !sensorTypeIsContinuous(mSensorType) ? 0
        : static_cast<uint32_t>(request.getLatency().toRawNanoseconds()
                                / kOneMicrosecondInNanoseconds),
  };

  if (req.enable && req.passive && !mPassiveSupported) {
    LOGD("Promoting sensor %" PRIu8 " passive request to active",
         static_cast<uint8_t>(getSensorType()));
  }

  SeeHelper *seeHelper = getSeeHelperForSensorType(getSensorType());
  bool wasInUImage = slpiInUImage();
  bool success = seeHelper->makeRequest(req);

  // If we dropped into micro-image during that blocking call to SEE, go back to
  // big image. This won't happen if the calling nanoapp is a big image one, but
  // other code paths currently assume that we will only transition from big
  // image to micro-image from CHRE's perspective while it's waiting for an
  // event to arrive in its empty queue.
  // TODO: transition back to big image only when needed, at the point of
  // invoking a nanoapp's free event/message callback
  if (!wasInUImage && slpiInUImage()) {
    LOGD("Restoring big image operating mode");
    slpiForceBigImage();
  }

  if (success) {
    if (request.getMode() == SensorMode::Off) {
      mLastEventValid = false;
    }

    // TODO: remove setSamplingStatus when .latency is available in status
    // update from SEE.
    struct chreSensorSamplingStatus status;
    if (getSamplingStatus(&status)) {

      // If passive request is not supported by this SEE sensor, it won't be
      // dynamically enabled/disabled and its status stays the same as set here.
      if (!mPassiveSupported) {
        status.enabled = req.enable;
      }
      status.latency = req.batchPeriodUs * kOneMicrosecondInNanoseconds;
      setSamplingStatus(status);
    }
  }
  return success;
}

bool PlatformSensor::flushAsync() {
  SensorType sensorType = getSensorType();
  return getSeeHelperForSensorType(sensorType)->flush(sensorType);
}

SensorType PlatformSensor::getSensorType() const {
  return mSensorType;
}

uint64_t PlatformSensor::getMinInterval() const {
  return mMinInterval;
}

const char *PlatformSensor::getSensorName() const {
  return mSensorName;
}

PlatformSensor::PlatformSensor(PlatformSensor&& other) {
  // Our move assignment operator doesn't assume that "this" is initialized, so
  // we can just use that here.
  *this = std::move(other);
}

PlatformSensor& PlatformSensor::operator=(PlatformSensor&& other) {
  // Note: if this implementation is ever changed to depend on "this" containing
  // initialized values, the move constructor implemenation must be updated.
  mSensorType = other.mSensorType;
  mMinInterval = other.mMinInterval;
  memcpy(mSensorName, other.mSensorName, kSensorNameMaxLen);

  mLastEvent = other.mLastEvent;
  other.mLastEvent = nullptr;

  mLastEventSize = other.mLastEventSize;
  other.mLastEventSize = 0;

  mLastEventValid = other.mLastEventValid;
  mSamplingStatus = other.mSamplingStatus;
  mPassiveSupported = other.mPassiveSupported;

  return *this;
}

ChreSensorData *PlatformSensor::getLastEvent() const {
  return mLastEventValid ? mLastEvent : nullptr;
}

bool PlatformSensor::getSamplingStatus(
    struct chreSensorSamplingStatus *status) const {
  CHRE_ASSERT(status);

  memcpy(status, &mSamplingStatus, sizeof(*status));
  return true;
}

bool PlatformSensor::getThreeAxisBias(
    struct chreSensorThreeAxisData *bias) const {
  SensorType sensorType = getSensorType();
  SeeCalHelper *calHelper =
      getSeeHelperForSensorType(sensorType)->getCalHelper();

  bool success = sensorTypeReportsBias(sensorType);
  if (success) {
    // We use the runtime-calibrated sensor type here, per documentation
    // of SeeCalHelper::getBias(), but overwrite the sensorHandle to that of
    // the curent sensor, because the calibration data itself is equivalent
    // for both calibrated/uncalibrated sensor types.
#ifdef CHRE_SLPI_UIMG_ENABLED
    // Use the uimg runtime-calibrated sensor type to get the calibration
    // bias, since SeeCalHelper is unaware of the bimg/uimg differentiation.
    SensorType calSensorType =
        toCalibratedSensorType(getUimgSensorType(sensorType));
#else
    SensorType calSensorType = toCalibratedSensorType(sensorType);
#endif
    if (calHelper->getBias(calSensorType, bias)) {
      bias->header.sensorHandle = getSensorHandleFromSensorType(sensorType);
    } else {
      // Set to zero value + unknown accuracy per CHRE API requirements.
      memset(bias, 0, sizeof(chreSensorThreeAxisData));
      bias->header.accuracy = CHRE_SENSOR_ACCURACY_UNKNOWN;
    }
  }

  return success;
}

void PlatformSensorBase::initBase(
    SensorType sensorType,uint64_t minInterval, const char *sensorName,
    ChreSensorData *lastEvent, size_t lastEventSize, bool passiveSupported) {
  mSensorType = sensorType;
  mMinInterval = minInterval;
  memcpy(mSensorName, sensorName, kSensorNameMaxLen);
  mLastEvent = lastEvent;
  mLastEventSize = lastEventSize;

  mSamplingStatus.enabled = false;
  mSamplingStatus.interval = CHRE_SENSOR_INTERVAL_DEFAULT;
  mSamplingStatus.latency = CHRE_SENSOR_LATENCY_DEFAULT;

  mPassiveSupported = passiveSupported;
}

void PlatformSensorBase::setLastEvent(const ChreSensorData *event) {
  memcpy(mLastEvent, event, mLastEventSize);
  mLastEventValid = true;
}

void PlatformSensorBase::setSamplingStatus(
    const struct chreSensorSamplingStatus& status) {
  mSamplingStatus = status;
}

}  // namespace chre