blob: 693014bbf9b686ad7364755774bc4e799cf43911 [file] [log] [blame]
/*
* 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.
*/
#ifndef CHRE_PLATFORM_SLPI_SEE_SEE_HELPER_H_
#define CHRE_PLATFORM_SLPI_SEE_SEE_HELPER_H_
extern "C" {
#include "sns_client.h"
} // extern "C"
#include "sns_suid.pb.h"
#include "chre/core/sensor_type.h"
#include "chre/platform/condition_variable.h"
#include "chre/platform/mutex.h"
#include "chre/platform/slpi/see/see_cal_helper.h"
#include "chre/util/dynamic_vector.h"
#include "chre/util/non_copyable.h"
#include "chre/util/optional.h"
#include "chre/util/time.h"
#include "chre/util/unique_ptr.h"
namespace chre {
inline bool suidsMatch(const sns_std_suid& suid0, const sns_std_suid& suid1) {
return (suid0.suid_high == suid1.suid_high
&& suid0.suid_low == suid1.suid_low);
}
//! A callback interface for receiving SeeHelper data events.
class SeeHelperCallbackInterface {
public:
struct SamplingStatusData {
SensorType sensorType;
struct chreSensorSamplingStatus status;
bool enabledValid;
bool intervalValid;
bool latencyValid;
};
virtual ~SeeHelperCallbackInterface() {}
//! Invoked by the SEE thread to update sampling status.
virtual void onSamplingStatusUpdate(
UniquePtr<SamplingStatusData>&& status) = 0;
//! Invoked by the SEE thread to provide sensor data events. The event data
//! format is one of the chreSensorXXXData defined in the CHRE API, implicitly
//! specified by sensorType.
virtual void onSensorDataEvent(
SensorType sensorType, UniquePtr<uint8_t>&& eventData) = 0;
//! Invoked by the SEE thread to update the AP wake/suspend status.
virtual void onHostWakeSuspendEvent(bool apAwake) = 0;
};
//! Default timeout for waitForService. Have a longer timeout since there may be
//! external dependencies blocking SEE initialization.
constexpr Nanoseconds kDefaultSeeWaitTimeout = Seconds(5);
//! Default timeout for sendReq response
constexpr Nanoseconds kDefaultSeeRespTimeout = Seconds(1);
//! Default timeout for sendReq indication
constexpr Nanoseconds kDefaultSeeIndTimeout = Seconds(2);
//! Length of the char array to store sensor string attributes.
constexpr size_t kSeeAttrStrValLen = 64;
//! A struct to facilitate getAttributesSync().
struct SeeAttributes {
char vendor[kSeeAttrStrValLen];
char name[kSeeAttrStrValLen];
char type[kSeeAttrStrValLen];
int64_t hwId;
float maxSampleRate;
uint8_t streamType;
bool passiveRequest;
};
//! A struct to facilitate making sensor request
struct SeeSensorRequest {
SensorType sensorType;
bool enable;
bool passive;
float samplingRateHz;
uint32_t batchPeriodUs;
};
/**
* A helper class for making requests to Qualcomm's Sensors Execution
* Environment (SEE) via the sns_client API and waiting for the response and the
* corresponding indication message if applicable.
* Not safe to use from multiple threads. Only one synchronous request can be
* made at a time.
*/
class SeeHelper : public NonCopyable {
public:
//! A struct to facilitate mapping between 'SUID + sns_client' and
//! SensorType.
struct SensorInfo {
sns_std_suid suid;
SensorType sensorType;
sns_client *client;
//! The SUID of the underlying physical sensor, different from suid if
//! resampler is used.
sns_std_suid physicalSuid;
};
/**
* Constructor for a SeeHelper that manages its own SeeCalHelper
*/
SeeHelper();
/**
* Constructor for a SeeHelper that uses the supplied SeeCalHelper object
* rather than creating its own. Caller must ensure that the lifetime of the
* SeeCalHelper object exceeds the lifetime of this SeeHelper instance.
*
* TODO: this would be a good case for a shared ptr implementation
*
* @param calHelper Non-null pointer to a calibration helper object to use
*/
SeeHelper(SeeCalHelper *calHelper);
/**
* Deinits clients before destructing this object.
*/
~SeeHelper();
/**
* Makes a request to SEE to enable an on-change sensor, with no additional
* payload. Can be used for registering a calibration sensor, for example.
*
* @param suid Sensor UID, usually determined via findSuidSync()
*
* @return true on success
*/
bool configureOnChangeSensor(const sns_std_suid& suid, bool enable);
/**
* A synchronous call to discover SUID(s) that supports the specified data
* type. This API will clear the provided dynamic vector before populating it.
*
* @param dataType A data type string, "accel" for example.
* @param suids A non-null pointer to a list of sensor UIDs that support the
* specified data type.
* @param minNumSuids The minimum number of SUIDs it needs to find before
* returning true. Otherwise, it'll re-try internally
* until it times out. It's illegal to set it to 0.
* @param maxRetries Maximum amount of times to retry looking up the SUID
* until giving up.
* @param retryDelay Time delay between retry attempts (msec).
*
* @return true if at least minNumSuids were successfully found
*/
bool findSuidSync(const char *dataType, DynamicVector<sns_std_suid> *suids,
uint8_t minNumSuids, uint32_t maxRetries,
Milliseconds retryDelay);
/**
* Version of findSuidSync providing default timeout/retry behavior.
*
* @see findSuidSync
*/
bool findSuidSync(const char *dataType, DynamicVector<sns_std_suid> *suids,
uint8_t minNumSuids = 1) {
uint32_t maxRetries = (mHaveTimedOutOnSuidLookup) ? 0 : 40;
return findSuidSync(dataType, suids, minNumSuids, maxRetries,
Milliseconds(250) /* retryDelay */);
}
/**
* A synchronous call to obtain the attributes of the specified SUID.
*
* @param suid The SUID of the sensor
* @param attr A non-null pointer to the attibutes of the specified SUID that
* include sensor vendor, name and max sampling rate, etc.
*
* @return true if the attribute was successfully obtained and attr populated.
*/
bool getAttributesSync(const sns_std_suid& suid, SeeAttributes *attr);
/**
* @return the SeeCalHelper instance used by this SeeHelper
*/
SeeCalHelper *getCalHelper() {
return mCalHelper;
}
/**
* Initializes and waits for the sensor client service to become available,
* and obtains remote_proc and cal sensors' info for future operations. This
* function must be called first to initialize the object and be called only
* once.
*
* @param cbIf A pointer to the callback interface that will be invoked to
* handle all async requests with callback data type defined in
* the interface.
* @param timeout The wait timeout in microseconds.
* @param skipDefaultSensorInit If true, don't register remote proc status and
* calibration sensors (e.g. if another SeeHelper
* instance will manage these)
*
* @return true if all initialization steps succeeded.
*/
bool init(SeeHelperCallbackInterface *cbIf,
Microseconds timeout = kDefaultSeeWaitTimeout,
bool skipDefaultSensorInit = false);
/**
* Makes a sensor request to SEE.
*
* @param request The sensor request to make.
*
* @return true if the request has been successfully made.
*/
bool makeRequest(const SeeSensorRequest& request);
/**
* Register a SensorType with the SUID of the SEE sensor/driver.
*
* Only registered SUIDs will call the indication callback provided in init()
* with populated CHRE sensor events. Each SUID/SensorType pair can only be
* registered once. It's illegal to register SensorType::Unknown.
*
* If an SUID is registered with a second SensorType, another client may be
* created to disambiguate the SUID representation.
*
* @param sensorType The SensorType to register.
* @param suid The SUID of the sensor.
* @param resample Whether to resample this sensorType.
* @param prevRegistered A non-null pointer to a boolean that indicates
* whether the SUID/SensorType pair has been previously registered.
*
* @return true if the SUID/SensorType pair was successfully registered.
*/
bool registerSensor(SensorType sensorType, const sns_std_suid& suid,
bool resample, bool *prevRegistered);
/**
* Checks whether the given SensorType has been successfully registered
* already via registerSensor().
*
* @param sensorType The SensorType to check.
*
* @return true if the given sensor type has been registered, false otherwise
*/
bool sensorIsRegistered(SensorType sensorType) const;
protected:
struct SnsClientApi {
decltype(sns_client_init) *sns_client_init;
decltype(sns_client_deinit) *sns_client_deinit;
decltype(sns_client_send) *sns_client_send;
};
//! Contains the API this SeeHelper instance uses to interact with SEE
const SnsClientApi *mSnsClientApi = &kDefaultApi;
/**
* Get the cached SUID of a calibration sensor that corresponds to the
* specified sensorType.
*
* @param sensorType The sensor type of the calibration sensor.
*
* @return A constant reference to the calibration sensor's SUID if present.
* Otherwise, a reference to sns_suid_sensor_init_zero is returned.
*/
const sns_std_suid& getCalSuidFromSensorType(SensorType sensorType) const {
return mCalHelper->getCalSuidFromSensorType(sensorType);
}
/**
* A convenience method to send a request and wait for the indication if it's
* a synchronous one using the default client obtained in init().
*
* @see sendReq
*/
bool sendReq(
const sns_std_suid& suid,
void *syncData, const char *syncDataType,
uint32_t msgId, void *payload, size_t payloadLen,
bool batchValid, uint32_t batchPeriodUs, bool passive,
bool waitForIndication,
Nanoseconds timeoutResp = kDefaultSeeRespTimeout,
Nanoseconds timeoutInd = kDefaultSeeIndTimeout) {
return sendReq(mSeeClients[0], suid,
syncData, syncDataType,
msgId, payload, payloadLen,
batchValid, batchPeriodUs, passive,
waitForIndication,
timeoutResp, timeoutInd);
}
private:
static const SnsClientApi kDefaultApi;
//! Used to synchronize responses and indications.
ConditionVariable mCond;
//! Used with mCond, and to protect access to member variables from other
//! threads.
Mutex mMutex;
//! Callback interface for sensor events.
SeeHelperCallbackInterface *mCbIf = nullptr;
//! The list of SEE clients initiated by SeeHelper.
DynamicVector<sns_client *> mSeeClients;
//! The list of SensorTypes registered and their corresponding SUID and
//! client.
DynamicVector<SensorInfo> mSensorInfos;
//! Data struct to store sync APIs data.
void *mSyncData = nullptr;
//! The data type whose indication this SeeHelper is waiting for in
//! findSuidSync.
const char *mSyncDataType = nullptr;
//! The SUID whose indication this SeeHelper is waiting for in a sync call.
sns_std_suid mSyncSuid = sns_suid_sensor_init_zero;
//! true if we are waiting on an indication for a sync call.
bool mWaitingOnInd = false;
//! true if we are waiting on a response of a request.
bool mWaitingOnResp = false;
//! true if we've timed out in findSuidSync at least once
bool mHaveTimedOutOnSuidLookup = false;
//! The response error of the request we just made.
sns_std_error mRespError;
//! A transaction ID that increments for each request.
uint32_t mCurrentTxnId = 0;
//! The SUID for the remote_proc sensor.
Optional<sns_std_suid> mRemoteProcSuid;
//! The SUID for the resampler sensor.
Optional<sns_std_suid> mResamplerSuid;
//! Handles sensor calibration data
SeeCalHelper *mCalHelper;
//! true if we own the memory to mCalHelper and should free it when done
bool mOwnsCalHelper;
/**
* Initializes the SEE remote processor sensor and makes a data request.
*
* @return true if the remote proc sensor was successfully initialized.
*/
bool initRemoteProcSensor();
/**
* Initializes the SEE resampler sensor.
*
* @return true if the resampler sensor was successfully initialized.
*/
bool initResamplerSensor();
/**
* Sends a request to SEE and waits for the response.
*
* @param client The pointer to sns_client to make the request with.
* @param req A pointer to the sns_client_request_msg to be sent.
* @param timeoutResp How long to wait for the response before abandoning it.
*
* @return true if the request was sent and the response was received
* successfully.
*/
bool sendSeeReqSync(sns_client *client, sns_client_request_msg *req,
Nanoseconds timeoutResp);
/**
* Wrapper to send a SEE request and wait for the indication if it's a
* synchronous one.
*
* Only one request can be pending at a time per instance of SeeHelper.
*
* @param client The pointer to sns_client to make requests with.
* @param suid The SUID of the sensor the request is sent to
* @param syncData The data struct or container to receive a sync call's data
* @param syncDataType The data type we are waiting for.
* @param msgId Message ID of the request to send
* @param payload A non-null pointer to the pb-encoded message
* @param payloadLen The length of payload
* @param batchValid Whether batchPeriodUs is valid and applicable to this
* request
* @param batchPeriodUs The batch period in microseconds
* @param passive Whether this is a passive request
* @param waitForIndication Whether to wait for the indication of the
* specified SUID or not.
* @param timeoutResp How long to wait for the response before abandoning it
* @param timeoutInd How long to wait for the indication before abandoning it
*
* @return true if the request has been sent and the response/indication it's
* waiting for has been successfully received
*/
bool sendReq(
sns_client *client, const sns_std_suid& suid,
void *syncData, const char *syncDataType,
uint32_t msgId, void *payload, size_t payloadLen,
bool batchValid, uint32_t batchPeriodUs, bool passive,
bool waitForIndication,
Nanoseconds timeoutResp = kDefaultSeeRespTimeout,
Nanoseconds timeoutInd = kDefaultSeeIndTimeout);
/**
* A helper function that prepares SeeHelper to wait for an indication.
*
* @see sendReq
*/
void prepareWaitForInd(const sns_std_suid& suid, void *syncData,
const char *syncDataType);
/**
* A helper function that waits for the indication.
*
* @return true if the inication is received before timeout.
*
* @see sendReq
*/
bool waitForInd(bool reqSent, Nanoseconds timeoutInd);
/**
* Handles the payload of a sns_client_event_msg.
*/
void handleSnsClientEventMsg(
sns_client *client, const void *payload, size_t payloadLen);
/**
* Handles a response from SEE for a request sent with the specified
* transaction ID.
*/
void handleSeeResp(uint32_t txnId, sns_std_error error);
/**
* Extracts "this" from cbData and calls through to handleSnsClientEventMsg()
*
* @see sns_client_ind
*/
static void seeIndCb(sns_client *client, void *msg, uint32_t msgLen,
void *cbData);
/**
* Extracts "this" from cbData and calls through to handleSeeResp()
*
* @see sns_client_resp
*/
static void seeRespCb(sns_client *client, sns_std_error error, void *cbData);
/**
* A wrapper to initialize a sns_client.
*
* @see sns_client_init
*/
bool waitForService(sns_client **client,
Microseconds timeout = kDefaultSeeWaitTimeout);
/**
* @return SensorInfo instance found in mSensorInfos with the given
* SensorType, or nullptr if not found
*/
const SensorInfo *getSensorInfo(SensorType sensorType) const;
};
#ifdef CHRE_SLPI_UIMG_ENABLED
/**
* A version of SeeHelper that explicitly uses the QMI API on the bottom edge
* and therefore only works in big image (but goes through CM instead of QCM
* within SEE).
*
* @see SeeHelper
*/
class BigImageSeeHelper : public SeeHelper {
public:
BigImageSeeHelper(SeeCalHelper *calHelper) : SeeHelper(calHelper) {
mSnsClientApi = &kQmiApi;
}
private:
static const SnsClientApi kQmiApi;
};
#endif // CHRE_SLPI_UIMG_ENABLED
} // namespace chre
#endif // CHRE_PLATFORM_SLPI_SEE_SEE_HELPER_H_