Revision control

Copy as Markdown

// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/private/qcore_ohos_p.h>
#include <QtCore/private/qohoslogger_p.h>
#include <ohossensorsmanager.h>
#include <ohossensorutils.h>
#include <algorithm>
#include <chrono>
#include <optional>
namespace {
std::optional<std::vector<float>> tryGetSensorEventData(::Sensor_Event *sensorEvent)
{
float *data = nullptr;
std::uint32_t len = 0;
std::int32_t getDataResult = ::OH_SensorEvent_GetData(sensorEvent, &data, &len);
if (getDataResult != ::SENSOR_SUCCESS) {
qOhosPrintfError("%s: OH_SensorEvent_GetData failed, code=%d", Q_FUNC_INFO, getDataResult);
return std::nullopt;
}
if (data == nullptr) {
qOhosPrintfError("%s: data pointer is null", Q_FUNC_INFO);
return std::nullopt;
}
return std::vector<float>(data, data + len);
}
std::shared_ptr<std::vector<::Sensor_Info *>> tryCreateInfos(std::uint32_t count)
{
::Sensor_Info **sensors = ::OH_Sensor_CreateInfos(count);
if (sensors == nullptr) {
qOhosPrintfError("%s: cannot create sensor infos objects", Q_FUNC_INFO);
return nullptr;
}
auto sensorsWrapper = std::shared_ptr<void>(
sensors,
[sensors, count](auto *) {
std::uint32_t destroyInfosResult = ::OH_Sensor_DestroyInfos(sensors, count);
if (destroyInfosResult != ::SENSOR_SUCCESS) {
qOhosPrintfError(
"%s: cannot destroy sensor infos, error: %d", Q_FUNC_INFO, destroyInfosResult);
}
}
);
return QtOhos::makeSharedPtrWithAttachedExtraData(
std::make_shared<std::vector<::Sensor_Info *>>(sensors, sensors + count),
sensorsWrapper);
}
std::shared_ptr<std::vector<::Sensor_Info *>> tryGetAvailableSensorsInfo()
{
std::uint32_t sensorsCount = 0;
std::uint32_t getSensorsCountResult = ::OH_Sensor_GetInfos(nullptr, &sensorsCount);
if (getSensorsCountResult != ::SENSOR_SUCCESS) {
qOhosPrintfError(
"%s: cannot get sensors count, error: %d", Q_FUNC_INFO, getSensorsCountResult);
return nullptr;
}
auto sensors = tryCreateInfos(sensorsCount);
if (!sensors) {
return nullptr;
}
std::uint32_t getInfosResult = ::OH_Sensor_GetInfos(sensors->data(), &sensorsCount);
if (getInfosResult != ::SENSOR_SUCCESS) {
qOhosPrintfError(
"%s: cannot get sensors infos, error: %d", Q_FUNC_INFO, getInfosResult);
return nullptr;
}
return sensors;
}
}
OhosSensorsManager::OhosSensorsManager()
{
QOhosJsThreadGateway::runAndWait(
[&](QOhosJsState &) {
m_jsScopeData = QtOhos::makeProxyWithJsThreadDeleter(std::make_shared<JsScopeData>());
m_jsScopeData->availableSensorsInfo = tryGetAvailableSensorsInfo();
m_jsScopeData->subscriber = tryCreateSensorResource<::Sensor_Subscriber>(
::OH_Sensor_CreateSubscriber, ::OH_Sensor_DestroySubscriber);
if (!m_jsScopeData->subscriber) {
qOhosReportFatalErrorAndAbort("%s: Failed to create sensor subscriber.", Q_FUNC_INFO);
}
std::int32_t setCallbackRetVal = ::OH_SensorSubscriber_SetCallback(
m_jsScopeData->subscriber.get(), OhosSensorsManager::sensorEventCallbackHandler);
if (setCallbackRetVal != ::SENSOR_SUCCESS) {
qOhosReportFatalErrorAndAbort(
"%s: OH_SensorSubscriber_SetCallback fail with error code: %d",
Q_FUNC_INFO, setCallbackRetVal);
}
});
}
OhosSensorsManager *OhosSensorsManager::instance()
{
static OhosSensorsManager sensorManager;
return &sensorManager;
}
std::vector<::Sensor_Type> OhosSensorsManager::getAvailableSensorsTypes()
{
return QOhosJsThreadGateway::eval(
[&](QOhosJsState &) {
std::vector<::Sensor_Type> result;
auto sensorsInfo = m_jsScopeData->availableSensorsInfo;
if (sensorsInfo) {
for (auto *sensorInfo : *sensorsInfo) {
auto sensorType = tryGetSensorInfoField<::Sensor_Type>(sensorInfo, ::OH_SensorInfo_GetType);
if (sensorType.has_value()) {
result.push_back(sensorType.value());
}
}
}
return result;
});
}
std::optional<OhosSensorCapabilities> OhosSensorsManager::tryGetSensorCapabilities(QSensor *sensor)
{
auto ohosSensorType = tryMapQtToOhosSensorType(sensor->type());
if (!ohosSensorType.has_value()) {
qOhosPrintfError(
"%s: Cannot map Qt sensor type: %s, to OHOS Sensor_Type",
Q_FUNC_INFO, sensor->type().toStdString().c_str());
return std::nullopt;
}
return QOhosJsThreadGateway::eval(
[&](QOhosJsState &) -> std::optional<OhosSensorCapabilities> {
auto availableSensorsInfo = m_jsScopeData->availableSensorsInfo;
if (!availableSensorsInfo) {
return std::nullopt;
}
auto sensorInfo = std::find_if(
availableSensorsInfo->begin(),
availableSensorsInfo->end(),
[&](auto *info) {
return tryGetSensorInfoField<::Sensor_Type>(info, ::OH_SensorInfo_GetType) == ohosSensorType;
});
if (sensorInfo == availableSensorsInfo->end()) {
qOhosPrintfError(
"%s: Cannot find a sensor info for a sensor of type: %d",
Q_FUNC_INFO, ohosSensorType.value());
return std::nullopt;
}
auto resolution = tryGetSensorInfoField<float>(*sensorInfo, ::OH_SensorInfo_GetResolution);
if (!resolution.has_value()) {
qOhosPrintfError(
"%s: Cannot get resolution for a sensor of type: %d", Q_FUNC_INFO, ohosSensorType.value());
return std::nullopt;
}
auto minSamplingIntervalInNs = tryGetSensorInfoField<std::int64_t>(
*sensorInfo, ::OH_SensorInfo_GetMinSamplingInterval);
if (!minSamplingIntervalInNs.has_value()) {
qOhosPrintfError(
"%s: Cannot get minimal sampling interval for a sensor of type: %d",
Q_FUNC_INFO, ohosSensorType.value());
return std::nullopt;
}
auto maxSamplingIntervalInNs = tryGetSensorInfoField<std::int64_t>(
*sensorInfo, ::OH_SensorInfo_GetMaxSamplingInterval);
if (!maxSamplingIntervalInNs.has_value()) {
qOhosPrintfError(
"%s: Cannot get maximal sampling interval for a sensor of type: %d",
Q_FUNC_INFO, ohosSensorType.value());
return std::nullopt;
}
auto samplingIntervalToDataRate =
[](std::int64_t intervalInNs) -> int {
return intervalInNs != 0
? 1e9 / intervalInNs
: 0;
};
return OhosSensorCapabilities{
resolution.value(),
samplingIntervalToDataRate(maxSamplingIntervalInNs.value()),
samplingIntervalToDataRate(minSamplingIntervalInNs.value())
};
});
}
void OhosSensorsManager::subscribeSensor(QSensor *sensor, QOhosConsumer<const OhosSensorData &> sensorDataConsumer)
{
auto subscribedSensor = m_subscribedSensors.find(sensor);
if (subscribedSensor != m_subscribedSensors.end()) {
qOhosPrintfError(
"%s: Sensor %s already subscribed.",
Q_FUNC_INFO, sensor->type().toStdString().c_str());
return;
}
auto ohosSensorType = tryMapQtToOhosSensorType(sensor->type());
if (!ohosSensorType.has_value()) {
qOhosPrintfError(
"%s: Cannot map Qt sensor type: %s, to OHOS Sensor_Type",
Q_FUNC_INFO, sensor->type().toStdString().c_str());
return;
}
auto sensorSubscriptionHandle = QOhosJsThreadGateway::eval(
[&](QOhosJsState &) -> std::shared_ptr<void> {
auto sensorSubId = tryCreateSensorResource<::Sensor_SubscriptionId>(
::OH_Sensor_CreateSubscriptionId, ::OH_Sensor_DestroySubscriptionId);
if (!sensorSubId) {
qOhosPrintfError("%s: OH_Sensor_CreateSubscriptionId return nullptr", Q_FUNC_INFO);
return nullptr;
}
std::int32_t idRetVal = ::OH_SensorSubscriptionId_SetType(sensorSubId.get(), ohosSensorType.value());
if (idRetVal != ::SENSOR_SUCCESS) {
qOhosPrintfError("%s: OH_Sensor_CreateSubscriptionId fail with error code: %d",
Q_FUNC_INFO, idRetVal);
return nullptr;
}
auto sensorSubAttr = tryCreateSensorResource<::Sensor_SubscriptionAttribute>(
::OH_Sensor_CreateSubscriptionAttribute, ::OH_Sensor_DestroySubscriptionAttribute);
if (!sensorSubAttr) {
qOhosPrintfError("%s: OH_Sensor_CreateSubscriptionAttribute returned nullptr", Q_FUNC_INFO);
return nullptr;
}
auto sensorSamplePeriod = std::chrono::duration<double>(1.0 / sensor->dataRate());
std::int32_t sensorSubAttrRetVal = ::OH_SensorSubscriptionAttribute_SetSamplingInterval(
sensorSubAttr.get(),
std::chrono::duration_cast<std::chrono::nanoseconds>(sensorSamplePeriod).count());
if (sensorSubAttrRetVal != ::SENSOR_SUCCESS) {
qOhosPrintfError(
"%s: OH_SensorSubscriptionAttribute_SetSamplingInterval fail with error code: %d",
Q_FUNC_INFO, sensorSubAttrRetVal);
return nullptr;
}
std::int32_t subscribeRetVal = ::OH_Sensor_Subscribe(
sensorSubId.get(), sensorSubAttr.get(), m_jsScopeData->subscriber.get());
if (subscribeRetVal != ::SENSOR_SUCCESS) {
qOhosPrintfError("%s: OH_Sensor_Subscribe fail with error code: %d",
Q_FUNC_INFO, subscribeRetVal);
return nullptr;
}
auto sensorSubscriptionHandle = std::shared_ptr<void>(
sensorSubId.get(),
[sensorSubId = std::move(sensorSubId),
weakSubscriber = std::weak_ptr<::Sensor_Subscriber>(m_jsScopeData->subscriber)](void *) mutable {
auto subscriber = weakSubscriber.lock();
if (subscriber) {
std::int32_t unsubRetVal = ::OH_Sensor_Unsubscribe(sensorSubId.get(), subscriber.get());
if (unsubRetVal != ::SENSOR_SUCCESS) {
qOhosPrintfError(
"%s: OH_Sensor_Unsubscribe fail with error code: %d",
Q_FUNC_INFO, unsubRetVal);
}
}
sensorSubId.reset();
});
return QtOhos::makeProxyWithJsThreadDeleter(std::move(sensorSubscriptionHandle));
});
if (sensorSubscriptionHandle) {
m_subscribedSensors.emplace(sensor, SensorSubscriptionHandle{sensorSubscriptionHandle, sensorDataConsumer});
}
}
void OhosSensorsManager::unsubscribeSensor(QSensor *sensor)
{
auto subscribedSensor = m_subscribedSensors.find(sensor);
if (subscribedSensor == m_subscribedSensors.end()) {
qOhosPrintfError(
"%s: Sensor %s not subscribed. Cannot unsubscribe.",
Q_FUNC_INFO, sensor->type().toStdString().c_str());
return;
}
m_subscribedSensors.erase(subscribedSensor);
}
void OhosSensorsManager::sensorEventCallbackHandler(::Sensor_Event *event)
{
if (event == nullptr) {
qOhosPrintfInfo("%s: sensor event is null", Q_FUNC_INFO);
return;
}
auto sensorType = tryGetSensorEventField<::Sensor_Type>(event, ::OH_SensorEvent_GetType);
if (!sensorType.has_value()) {
qOhosPrintfError("%s: Cannot obtain sensor type from event.", Q_FUNC_INFO);
return;
}
auto timestamp = tryGetSensorEventField<std::int64_t>(event, ::OH_SensorEvent_GetTimestamp);
if (!timestamp.has_value()) {
qOhosPrintfError("%s: Cannot obtain timestamp from event.", Q_FUNC_INFO);
return;
}
auto accuracy = tryGetSensorEventField<::Sensor_Accuracy>(event, ::OH_SensorEvent_GetAccuracy);
if (!accuracy.has_value()) {
qOhosPrintfError("%s: Cannot obtain sensor accuracy from event.", Q_FUNC_INFO);
return;
}
auto data = tryGetSensorEventData(event);
if (!data.has_value()) {
qOhosPrintfError("%s: Cannot obtain sensor data from event.", Q_FUNC_INFO);
return;
}
OhosSensorData sensorData{timestamp.value(), accuracy.value(), data.value()};
QtOhos::invokeInQtThread(
[sensorType, sensorData]() {
auto sensorDataConsumer =
OhosSensorsManager::instance()->tryGetSensorConsumerForGivenOhosSensorType(sensorType.value());
if (sensorDataConsumer != nullptr) {
sensorDataConsumer(sensorData);
}
});
}
QOhosConsumer<const OhosSensorData &>
OhosSensorsManager::tryGetSensorConsumerForGivenOhosSensorType(::Sensor_Type ohosSensorType)
{
auto sensor = std::find_if(
m_subscribedSensors.begin(),
m_subscribedSensors.end(),
[&](const auto &kv) {
return kv.first->identifier() == QByteArray::number(ohosSensorType);
});
if (sensor == m_subscribedSensors.end()) {
qOhosPrintfError(
"%s: Sensor with identifier %d is not subscribed.",
Q_FUNC_INFO, ohosSensorType);
return nullptr;
}
return sensor->second.sensorDataConsumer;
}