社区编辑申请
注册/登录
OpenHarmony 源码解析之Sensor子系统(上)
开发 前端
本文主要和大家分享传感器应用到框架层的实现,重点分析了传感器订阅、启动以及接收订阅传感器数据,做了较为详细的代码说明,希望通过本文您能初步掌握JS应用开发到框架层开发的步骤与流程。

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

前言

人类获取外界信息必须借助于感觉器官,而在研究自然现象和规律以及生产活动仅靠感官已经远远不够了,为了适应这种情况,出现了传感器。随着物联网,移动互联网的快速发展,在数字时代,传感器在智能交通,智能工业,智能穿戴等领域有着广阔的应用空间。

概述

传感器是检测到被测量信息,将非电量信息转换成电信号的检测装置。就像眼睛是人类心灵的窗户,传感器则是计算机感知世界万物的眼睛。

传感器用于侦测环境中所发生事件或变化,并将此消息发送至其他电子设备(如中央处理器)的设备,通常由敏感组件和转换组件组成。根据用途可分为以下六大类:

  • 运动类:加速度、陀螺仪、重力、线性加速度传感器等;
  • 姿态类:旋转矢量、方向传感器等;
  • 环境类:磁力计、气压、湿度传感器等;
  • 光线类:环境光、接近光、色温传感器等;
  • 健康类:心率、心跳传感器等;
  • 其它:霍尔传感器、手握传感器等;

架构层级

OpenHarmony架构图:

#星光计划1.0# OpenHarmony 源码解析之Sensor子系统(上)-鸿蒙HarmonyOS技术社区

传感器架构图如下所示:

#星光计划1.0# OpenHarmony 源码解析之Sensor子系统(上)-鸿蒙HarmonyOS技术社区

应用层 :各种需要sensor的应用,例如运动健康,计步器,指南针等等。

框架层 :

  1. SDK ,给应用提供标准接口,包括JS接口和C++接口。
  2. Framework,向应用层提供稳定的基础能力,包括Sensor列表查询、Sensor启停、Sensor订阅及去订阅,Sensor参数配置,创建数据传递通道,sensor数据上传等功能。
  3. Service, 提供Sensor设备管理,Sensor通用配置能力,Sensor通用数据解析能力,权限管理能力。

HDF层 :HDF驱动框架,Sensor设备驱动的开发是基于该框架的基础上,结合操作系统适配层(OSAL)和平台驱动接口(比如I2C/SPI/UART总线等平台资源)能力,屏蔽不同操作系统和平台总线资源差异,实现Sensor驱动“一次开发,多系统部署”的目标。

Hardware层 :各种传感器器件,例如加速度计,陀螺仪,温度,湿度等等。

Sensor子系统代码目录

  1. /base/sensors/sensor 
  2.  
  3. ├── frameworks   # 框架代码 
  4.  
  5. │ └── native     # sensor客户端代码 
  6.  
  7. ├── interfaces   # 对外接口存放目录 
  8.  
  9. │ ├── native     # sensor native实现 
  10.  
  11. │ └── plugin     # Js API 
  12.  
  13. ├── sa_profile   # 服务名称和服务的动态库的配置文件 
  14.  
  15. ├── services     # 服务的代码目录 
  16.  
  17. │ └── sensor     # 传感器服务,包括加速度、陀螺仪等,上报传感器数据 
  18.  
  19. └── utils        # 公共代码,包括权限、通信等能力 

源码分析

本文先讲解框架层的代码,HDF的部分放在下一篇文章讲解。框架层主要包含两部分:

JS应用订阅、启动sensor。

JS应用收到订阅sensor的数据信息。

1. JS应用订阅、启动Sensor

我们从JS API开放的能力开始看源码,绿色部分看作client,黄色部分看作service。

#星光计划1.0# OpenHarmony 源码解析之Sensor子系统(上)-鸿蒙HarmonyOS技术社区

JS API的主要接口:

给JS应用提供接口的实现文件是sensor_js.cpp,我们从init开始看接口的实现:

  1. static napi_value Init(napi_env env, napi_value exports) 
  2. {    
  3.     // 这里定义了三个接口,on、once、off。 
  4.     napi_property_descriptor desc[] = { 
  5.         DECLARE_NAPI_FUNCTION("on"On), 
  6.         DECLARE_NAPI_FUNCTION("once", Once), 
  7.         DECLARE_NAPI_FUNCTION("off"Off
  8.     }; 
  9.     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc)); 
  10.     return exports; 
  11.  
  12. static napi_value On(napi_env env, napi_callback_info info) 
  13.     ...... 
  14.     // 获取JS应用传递的sensorTypeId,例如加速度计,陀螺仪等等 
  15.     int32_t sensorTypeId = GetCppInt32(args[0], env); 
  16.     ...... 
  17.     AsyncCallbackInfo *asyncCallbackInfo = new AsyncCallbackInfo { 
  18.         .env = env, 
  19.         .asyncWork = nullptr, 
  20.         .deferred = nullptr, 
  21.     }; 
  22.     napi_create_reference(env, args[1], 1, &asyncCallbackInfo->callback[0]); 
  23.     g_onCallbackInfos[sensorTypeId] = asyncCallbackInfo; 
  24.     // 调用SubscribeSensor函数订阅该sensor,指定sensor类型,上报频率,数据返回通过DataCallbackImpl。 
  25.     int32_t ret = SubscribeSensor(sensorTypeId, interval, DataCallbackImpl); 
  26.     ...... 
  27.     HiLog::Info(LABEL, "%{public}s out", __func__); 
  28.     return nullptr; 
  29.  
  30. static int32_t SubscribeSensor(int32_t sensorTypeId, int64_t interval, RecordSensorCallback callback) 
  31.     HiLog::Info(LABEL, "%{public}s in, sensorTypeId: %{public}d", __func__, sensorTypeId); 
  32.     // 注一:订阅指定sensorId的传感器数据,通过user,系统将向应用上报获得的传感器数据,user实际就是callback。 
  33.     int32_t ret = SubscribeSensor(sensorTypeId, &user); 
  34.     if (ret < 0) { 
  35.         HiLog::Error(LABEL, "%{public}s subscribeSensor failed", __func__); 
  36.         return ret; 
  37.     } 
  38.     // 设置采样频率和上报频率 
  39.     ret = SetBatch(sensorTypeId, &user, interval, 0); 
  40.     if (ret < 0) { 
  41.         HiLog::Error(LABEL, "%{public}s set batch failed", __func__); 
  42.         return ret; 
  43.     } 
  44.     //注二: 启用已订阅的传感器。只有在启用传感器后,应用才能获取传感器数据。 
  45.     ret = ActivateSensor(sensorTypeId, &user); 
  46.     if (ret < 0) { 
  47.         HiLog::Error(LABEL, "%{public}s activateSensor failed", __func__); 
  48.         return ret; 
  49.     } 
  50.     return 0; 

注一:SubscribeSensor,订阅sensor,建立sensor数据传递频道。

  1. int32_t SensorAgentProxy::SubscribeSensor(int32_t sensorId, const SensorUser *user) const 
  2.     HiLog::Info(LABEL, "%{public}s in, sensorId: %{public}d", __func__, sensorId); 
  3.     if (user == nullptr || sensorId < 0 || user->callback == nullptr) { 
  4.         HiLog::Error(LABEL, "%{public}s user is null or sensorId is invalid", __func__); 
  5.         return OHOS::Sensors::ERROR; 
  6.     } 
  7.     if (!g_isChannelCreated) { 
  8.         HiLog::Info(LABEL, "%{public}s channel created", __func__); 
  9.         g_isChannelCreated = true
  10.         // 创建sensor数据频道,通过此channel实现client和service的数据传递。 
  11.         CreateSensorDataChannel(user); 
  12.     } 
  13.     // 指定sensorId对应的callback 
  14.     g_subscribeMap[sensorId] = user
  15.     return OHOS::Sensors::SUCCESS; 
  16.  
  17. int32_t SensorAgentProxy::CreateSensorDataChannel(const SensorUser *user) const 
  18.     HiLog::Debug(LABEL, "%{public}s", __func__); 
  19.     if (dataChannel_ == nullptr) { 
  20.         HiLog::Error(LABEL, "%{public}s data channel cannot be null", __func__); 
  21.         return INVALID_POINTER; 
  22.     } 
  23.     // 注1 ,创建sensor数据传递频道,sendFd和recvFd 
  24.     auto ret = dataChannel_->CreateSensorDataChannel(HandleSensorData, nullptr); 
  25.     if (ret != ERR_OK) { 
  26.         HiLog::Error(LABEL, "%{public}s create data channel failed, ret : %{public}d", __func__, ret); 
  27.         return ret; 
  28.     } 
  29.     auto &client = SensorServiceClient::GetInstance(); 
  30.     // 注2 , 将client创建的数据频道,sendFd转移到service,使得service和client可以通讯。 
  31.     ret = client.TransferDataChannel(dataChannel_); 
  32.     if (ret != ERR_OK) { 
  33.         auto destoryRet = dataChannel_->DestroySensorDataChannel(); 
  34.         HiLog::Error(LABEL, "%{public}s transfer data channel failed,  
  35.                      ret : %{public}d, destoryRet : %{public}d",__func__, ret, destoryRet); 
  36.         return ret; 
  37.     } 
  38.     return ERR_OK; 

先看注1,创建sensor数据传递频道,sendFd和receiveFd,由调用关系找到,调用SensorDataChannel::InnerSensorDataChannel(),我们来看下这个函数。

  1. int32_t SensorDataChannel::InnerSensorDataChannel() 
  2.     std::lock_guard<std::mutex> threadLock(treadMutex_); 
  3.     // create basic data channel,通过socketpair()函数用于创建一对套接字sendFd_和receiveFd_ 
  4.     int32_t ret = CreateSensorBasicChannel(SENSOR_READ_DATA_SIZE,SENSOR_READ_DATA_SIZE); 
  5.     if (ret != ERR_OK) { 
  6.         HiLog::Error(LABEL, "%{public}s create basic channel failed, ret : %{public}d", __func__, ret); 
  7.         return ret; 
  8.     } 
  9.     auto listener = std::make_shared<MyFileDescriptorListener>(); 
  10.     listener->SetChannel(this); 
  11.     auto myRunner = AppExecFwk::EventRunner::Create(true); 
  12.     if (myRunner == nullptr) { 
  13.         HiLog::Error(LABEL, "%{public}s myRunner is null", __func__); 
  14.         return -1; 
  15.     } 
  16.     auto handler = std::make_shared<MyEventHandler>(myRunner); 
  17.     if (handler == nullptr) { 
  18.         HiLog::Error(LABEL, "%{public}s handler is null", __func__); 
  19.         return -1; 
  20.     } 
  21.     // receiveFd_绑定到MyFileDescriptorListener,MyFileDescriptorListener用于接收sensor数据 
  22.     receiveFd_ = GetReceiveDataFd(); 
  23.     auto inResult = handler->AddFileDescriptorListener(receiveFd_, AppExecFwk::FILE_DESCRIPTOR_INPUT_EVENT, listener); 
  24.     …… 

再看注2,如何将sendFd_转移给service,作为sensor数据的发送端?

  1. ErrCode SensorServiceProxy::TransferDataChannel(const sptr<SensorBasicDataChannel> &sensorBasicDataChannel, 
  2.                                                 const sptr<IRemoteObject> &sensorClient) 
  3.     HiLog::Debug(LABEL, "%{public}s sendFd: %{public}d", __func__, sensorBasicDataChannel->GetSendDataFd()); 
  4.     if (sensorBasicDataChannel == nullptr || sensorClient == nullptr) { 
  5.         HiLog::Error(LABEL, "%{public}s sensorBasicDataChannel or sensorClient cannot be null", __func__); 
  6.         return OBJECT_NULL; 
  7.     } 
  8.     MessageParcel data; 
  9.     MessageParcel reply; 
  10.     MessageOption option
  11.     if (!data.WriteInterfaceToken(SensorServiceProxy::GetDescriptor())) { 
  12.         HiLog::Error(LABEL, "%{public}s write descriptor failed", __func__); 
  13.         return WRITE_MSG_ERR; 
  14.     } 
  15.     // 将sendFd_写入parcel,会通过SendRequest,传递给service 
  16.     sensorBasicDataChannel->SendToBinder(data); 
  17.     if (!data.WriteRemoteObject(sensorClient)) { 
  18.         HiLog::Error(LABEL, "%{public}s write sensorClient failed", __func__); 
  19.         return WRITE_MSG_ERR; 
  20.     } 
  21.     // IPC通讯机制,执行此处会调用service的CreateDataChannelInner 
  22.     int32_t ret = Remote()->SendRequest(ISensorService::TRANSFER_DATA_CHANNEL, data, reply, option); 
  23.     if (ret != NO_ERROR) { 
  24.         DmdReport::ReportException(SENSOR_SERVICE_IPC_EXCEPTION, "TransferDataChannel", ret); 
  25.         HiLog::Error(LABEL, "%{public}s failed, ret : %{public}d", __func__, ret); 
  26.     } 
  27.     sensorBasicDataChannel->CloseSendFd(); 
  28.     return static_cast<ErrCode>(ret); 

由SendRequest,指定ISensorService::TRANSFER_DATA_CHANNEL会调用到CreateDataChannelInner,这个函数主要的作用是CreateSensorBasicChannel,service端获取到sendFd_。

  1. ErrCode SensorServiceStub::CreateDataChannelInner(MessageParcel &data, MessageParcel &reply) 
  2.     (void)reply; 
  3.     sptr<SensorBasicDataChannel> sensorChannel = new (std::nothrow)SensorBasicDataChannel(); 
  4.     if (sensorChannel == nullptr) { 
  5.         HiLog::Error(LABEL, "%{public}s sensorChannel cannot be null", __func__); 
  6.         return OBJECT_NULL; 
  7.     } 
  8.     auto ret = sensorChannel->CreateSensorBasicChannel(data); 
  9.     if (ret != ERR_OK) { 
  10.         HiLog::Error(LABEL, "%{public}s CreateSensorBasicChannel ret : %{public}d",__func__, ret); 
  11.         return OBJECT_NULL; 
  12.     } 
  13.     sptr<IRemoteObject> sensorClient = data.ReadRemoteObject(); 
  14.     if (sensorClient == nullptr) { 
  15.         HiLog::Error(LABEL, "%{public}s sensorClient cannot be null", __func__); 
  16.         return OBJECT_NULL; 
  17.     } 
  18.     return TransferDataChannel(sensorChannel, sensorClient); 
  19.  
  20. int32_t SensorBasicDataChannel::CreateSensorBasicChannel(MessageParcel &data) 
  21.     HiLog::Debug(LABEL, "%{public}s begin", __func__); 
  22.     if ((sendFd_ != INVALID_FD) || (receiveFd_ != INVALID_FD)) { 
  23.         HiLog::Debug(LABEL, "%{public}s already create socketpair", __func__); 
  24.         return ERR_OK; 
  25.     } 
  26.     int32_t tmpFd = data.ReadFileDescriptor(); 
  27.     if (tmpFd < 0) { 
  28.         HiLog::Error(LABEL, "%{public}s ReadFileDescriptor failed", __func__); 
  29.         sendFd_ = INVALID_FD; 
  30.         return SENSOR_CHANNEL_DUP_ERR; 
  31.     } 
  32.     // service的sendFd,和前面的receiveFd对应,用于传递sensor数据。 
  33.     sendFd_ = dup(tmpFd); 
  34.     HiLog::Error(LABEL, "%{public}s sendFd: %{public}d", __func__, sendFd_); 
  35.     if (sendFd_ < 0) { 
  36.         HiLog::Error(LABEL, "%{public}s dup FileDescriptor failed", __func__); 
  37.         sendFd_ = INVALID_FD; 
  38.         return SENSOR_CHANNEL_DUP_ERR; 
  39.     } 
  40.     return ERR_OK; 

至此client和service跨进程传递Sensor数据的通道建立完成了。

注二: 启用已订阅的传感器。

  1. int32_t ActivateSensor(int32_t sensorId, const SensorUser *user
  2.     HiLog::Info(LABEL, "%{public}s begin", __func__); 
  3.     const SensorAgentProxy *proxy = GetInstance(); 
  4.     if (proxy == NULL) { 
  5.         HiLog::Error(LABEL, "%s proxy is null", __func__); 
  6.         return OHOS::Sensors::ERROR; 
  7.     } 
  8.     // 调用SensorAgentProxy的ActivateSensor函数,指定sendorId和user,开启sensor 
  9.     return proxy->ActivateSensor(sensorId, user); 
  10.  
  11. int32_t SensorAgentProxy::ActivateSensor(int32_t sensorId, const SensorUser *user) const 
  12.     if (user == NULL || sensorId < 0) { 
  13.         HiLog::Error(LABEL, "%{public}s user is null or sensorId is invalid",__func__); 
  14.         return OHOS::Sensors::ERROR; 
  15.     } 
  16.     if (g_samplingInterval < 0 || g_reportInterval < 0) { 
  17.         HiLog::Error(LABEL, "%{public}s samplingPeroid or g_reportInterval is invalid", __func__); 
  18.         return OHOS::Sensors::ERROR; 
  19.     } 
  20.     if ((g_subscribeMap.find(sensorId) == g_subscribeMap.end()) || (g_subscribeMap.at(sensorId) != user)) { 
  21.         HiLog::Error(LABEL, "%{public}s subscribe sensorId first", __func__); 
  22.         return OHOS::Sensors::ERROR; 
  23.     } 
  24.     SensorServiceClient &client = SensorServiceClient::GetInstance(); 
  25.     // 调用SensorServiceClient的 EnableSensor,指定sensorId,采样频率设上报频率。 
  26.     int32_t ret = client.EnableSensor(sensorId, g_samplingInterval, g_reportInterval); 
  27.     g_samplingInterval = -1; 
  28.     g_reportInterval = -1; 
  29.     if (ret != 0) { 
  30.         HiLog::Error(LABEL, "%{public}s enable sensor failed, ret: %{public}d",__func__, ret); 
  31.         return OHOS::Sensors::ERROR; 
  32.     } 
  33.     return OHOS::Sensors::SUCCESS; 

最终会调用到SensorServiceImpl::EnableSensor,这里主要是调用HDF提供的标准接口,打开sensor,下一篇文章会讲述HDF的内容。

  1. ErrCode SensorServiceImpl::EnableSensor(uint32_t sensorId) const 
  2.     HiLog::Info(LABEL, "%{public}s begin", __func__); 
  3.     int32_t ret = sensorInterface_->Enable(sensorId); 
  4.     if (ret < 0) { 
  5.         HiLog::Error(LABEL, "%{public}s is failed", __func__); 
  6.         return -1; 
  7.     } 
  8.     HiLog::Info(LABEL, "%{public}s end", __func__); 
  9.     return ERR_OK; 

2. JS应用接收订阅的sensor数据

#星光计划1.0# OpenHarmony 源码解析之Sensor子系统(上)-鸿蒙HarmonyOS技术社区

Sensor打开之后,就会有sensor数据按照上报频率上报给应用。我们下面看下,数据是如何上报的?

前面看到传递的数据通道在订阅时已经创建好了,SensorService::EnableSensor时,在其内部还调用了SaveSubscriber。

  1. ErrCode SensorService::EnableSensor(uint32_t sensorId, int64_t samplingPeriodNs, int64_t maxReportDelayNs) 
  2.     ...... 
  3.     auto ret = SaveSubscriber(sensorId, samplingPeriodNs, maxReportDelayNs); 
  4.     if (ret != ERR_OK) { 
  5.         HiLog::Error(LABEL, "%{public}s SaveSubscriber failed", __func__); 
  6.         return ret; 
  7.     } 
  8.     ret = sensorServiceImpl_.EnableSensor(sensorId); 
  9.     if (ret != ERR_OK) { 
  10.         HiLog::Error(LABEL, "%{public}s EnableSensor failed", __func__); 
  11.         clientInfo_.RemoveSubscriber(sensorId, this->GetCallingPid()); 
  12.         return ENABLE_SENSOR_ERR; 
  13.     } 
  14.     return ret; 

SaveSubscriber 做了两件事情:

1、调用SensorManager::SaveSubscriber管理sensor订阅信息。

2、开启sensor数据上报的线程。

  1. ErrCode SensorService::SaveSubscriber(uint32_t sensorId, int64_t samplingPeriodNs, int64_t maxReportDelayNs) 
  2.     auto ret = sensorManager_.SaveSubscriber(sensorId, this->GetCallingPid(), samplingPeriodNs, maxReportDelayNs); 
  3.     if (ret != ERR_OK) { 
  4.         HiLog::Error(LABEL, "%{public}s SaveSubscriber failed", __func__); 
  5.         return ret; 
  6.     } 
  7.     sensorManager_.StartDataReportThread(); 
  8.     if (!sensorManager_.SetBestSensorParams(sensorId, samplingPeriodNs, maxReportDelayNs)) { 
  9.         HiLog::Error(LABEL, "%{public}s SetBestSensorParams failed", __func__); 
  10.         clientInfo_.RemoveSubscriber(sensorId, this->GetCallingPid()); 
  11.         return ENABLE_SENSOR_ERR; 
  12.     } 
  13.     return ret; 
  14.  
  15. void SensorManager::StartDataReportThread() 
  16.     HiLog::Debug(LABEL, "%{public}s begin", __func__); 
  17.     if (!dataThread_.joinable()) { 
  18.         HiLog::Warn(LABEL, "%{public}s dataThread_ started", __func__); 
  19.         std::thread senocdDataThread(SensorDataProcesser::DataThread, sensorDataProcesser_, reportDataCallback_); 
  20.         dataThread_ = std::move(senocdDataThread); 
  21.     } 
  22.     HiLog::Debug(LABEL, "%{public}s end", __func__); 
  23.  
  24. int32_t SensorDataProcesser::DataThread(sptr<SensorDataProcesser>dataProcesser, sptr<ReportDataCallback> dataCallback) 
  25.     HiLog::Debug(LABEL, "%{public}s begin", __func__); 
  26.     do { 
  27.         if (dataProcesser->ProcessEvents(dataCallback) == INVALID_POINTER) { 
  28.             HiLog::Error(LABEL, "%{public}s callback cannot be null", __func__); 
  29.             return INVALID_POINTER; 
  30.         } 
  31.     } while (1); 
  32.  
  33. int32_t SensorDataProcesser::ProcessEvents(sptr<ReportDataCallback>dataCallback) 
  34.     if (dataCallback == nullptr) { 
  35.         HiLog::Error(LABEL, "%{public}s dataCallback cannot be null", __func__); 
  36.         return INVALID_POINTER; 
  37.     } 
  38.     std::unique_lock<std::mutex> lk(SensorServiceImpl::dataMutex_); 
  39.     // 使用std::condition_variable::wait(),处于阻塞状态, 
  40.     // 当其它线程调用notify_one()或者notify_all()函数,wait()会结束阻塞。 
  41.     SensorServiceImpl::dataCondition_.wait(lk); 
  42.     ...... 
  43.     return SUCCESS; 

看到这里,我们发现SaveSubscriber创建了sensor数据处理的线程,并使用SensorServiceImpl::dataCondition_.wait(lk)进入阻塞状态,我们看下何时使用notify_one()来激活该线程上报数据的?

系统开机启动时,hsensors进程启动,也就是SensorService启动。

  1. on post-fs-data 
  2. start hsensors 
  3. service hsensors /system/bin/sa_main /system/profile/hsensors.xml 
  4. class hsensors 
  5. user system 
  6. group system shell 
  7. seclabel u:r:foundation:s0 

SensorService启动后,会将ZReportDataCallback 注册到HDF,看下面的代码:

  1. void SensorService::OnStart() 
  2.     if (state_ == SensorServiceState::STATE_RUNNING) { 
  3.         HiLog::Warn(LABEL, "%{public}s SensorService has already started", __func__); 
  4.         return
  5.     } 
  6.     // 调用HDF标准接口,初始化 
  7.     if (!InitInterface()) { 
  8.         HiLog::Error(LABEL, "%{public}s Init interface error", __func__); 
  9.         return
  10.     } 
  11.     // 注册数据返回的callback,初始化 
  12.     if (!InitDataCallback()) { 
  13.         HiLog::Error(LABEL, "%{public}s Init data callback error", __func__); 
  14.         return
  15.     } 
  16.     ...... 
  17.  
  18. bool SensorService::InitDataCallback() 
  19.     reportDataCallback_ = new (std::nothrow) ReportDataCallback(); 
  20.     if (reportDataCallback_ == nullptr) { 
  21.         HiLog::Error(LABEL, "%{public}s failed, reportDataCallback_ cannot be null",__func__); 
  22.         return false
  23.     } 
  24.     // 将ZReportDataCallback通过RegisteDataReport赋值给reportDataCb_,sensor数据上报会触发ZReportDataCallback 
  25.     // new ReportDataCallback传递到sensorServiceImpl_,为了调用reportDataCb_ 
  26.     ZReportDataCb cb = &ReportDataCallback::ZReportDataCallback; 
  27.     auto ret = sensorServiceImpl_.RegisteDataReport(cb, reportDataCallback_); 
  28.     if (ret != ERR_OK) { 
  29.         HiLog::Error(LABEL, "%{public}s RegisterDataReport failed", __func__); 
  30.         return false
  31.     } 
  32.     return true
  1. ErrCode SensorServiceImpl::RegisteDataReport(ZReportDataCb cb, sptr<ReportDataCallback> reportDataCallback) 
  2.     HiLog::Info(LABEL, "%{public}s begin", __func__); 
  3.     if (reportDataCallback == nullptr) { 
  4.         HiLog::Error(LABEL, "%{public}s failed, reportDataCallback cannot be null",__func__); 
  5.         return ERR_NO_INIT; 
  6.     } 
  7.     // 注册callback到HDF 
  8.     Register(SensorDataCallback); 
  9.     reportDataCb_ = cb; 
  10.     reportDataCallback_ = reportDataCallback; 
  11.     HiLog::Info(LABEL, "%{public}s end", __func__); 
  12.     return ERR_OK; 
  13.  
  14. ErrCode SensorServiceImpl::Register(RecordDataCallback cb) const 
  15.     HiLog::Info(LABEL, "%{public}s begin", __func__); 
  16.     if (sensorInterface_ == nullptr) { 
  17.         HiLog::Error(LABEL, " %{public}s,""test sensorHdi get Module instance failed\n\r"); 
  18.         return ERR_INVALID_VALUE; 
  19.     } 
  20.     // 通过HDF提供的标准接口,注册到HDF 
  21.     int32_t ret = sensorInterface_->Register(cb); 
  22.     if (ret < 0) { 
  23.         HiLog::Error(LABEL, "%{public}s failed", __func__); 
  24.         return ERR_INVALID_VALUE; 
  25.     } 
  26.     HiLog::Info(LABEL, "%{public}s end", __func__); 
  27.     return ERR_OK; 

当JS应用订阅了传感器,并且启用了传感器,传感器数据就从SensorServiceImpl::SensorDataCallback向上传递,我们看下这函数的实现,主要做了两件事情:

1、调用ReportDataCallback::ZreportDataCallback将sensor数据写入cb->eventsBuf_。

2、调用dataCondition_.notify_one()激活数据上报的线程。

  1. int32_t SensorServiceImpl::SensorDataCallback(const struct SensorEvents *event) 
  2.     HiLog::Debug(LABEL, "%{public}s begin", __func__); 
  3.     const int32_t SENSOR_AXISZ = 2; 
  4.     if ((event == nullptr) || (event->dataLen == 0)) { 
  5.         HiLog::Error(LABEL, "%{public}s event is NULL", __func__); 
  6.         return ERR_INVALID_VALUE; 
  7.     } 
  8.     float *data = (float*)event->data; 
  9.     if (reportDataCb_ == nullptr) { 
  10.         HiLog::Error(LABEL, "%{public}s reportDataCb_ cannot be null", __func__); 
  11.         return ERR_INVALID_VALUE; 
  12.     } 
  13.     // 调用ReportDataCallback::ZReportDataCallback方法,存入eventsBuf_ 
  14.     (void)(reportDataCallback_->*reportDataCb_)(reinterpret_cast<const structSensorEvent*>(event), reportDataCallback_); 
  15.     // 激活sensor数据上报线程 
  16.     dataCondition_.notify_one(); 
  17.     return ERR_OK; 
  18.  
  19. int32_t ReportDataCallback::ZReportDataCallback(const struct SensorEvent *event, sptr<ReportDataCallback> cb) 
  20.     float *data = (float*)event->data; 
  21.     if (cb == nullptr || cb->eventsBuf_.circularBuf == nullptr || event == nullptr) { 
  22.         HiLog::Error(LABEL, "%{public}s callback or circularBuf or event cannot be null", __func__); 
  23.         return ERROR; 
  24.     } 
  25.     struct SensorEvent eventCopy = { 
  26.         .sensorTypeId = event->sensorTypeId, 
  27.         .version = event->version, 
  28.         .timestamp = event->timestamp
  29.         .option = event->option
  30.         .mode = event->mode, 
  31.         .dataLen = event->dataLen 
  32.     }; 
  33.     eventCopy.data = new uint8_t[SENSOR_DATA_LENGHT]; 
  34.     if (memcpy_s(eventCopy.data, event->dataLen, event->data, event->dataLen) != EOK) { 
  35.         HiLog::Error(LABEL, "%{public}s copy data failed", __func__); 
  36.         return COPY_ERR; 
  37.     } 
  38.     // 将SensorEvent的数据存入到ReportDataCallback的变量eventsBuf_里面 
  39.     int32_t leftSize = CIRCULAR_BUF_LEN - cb->eventsBuf_.eventNum; 
  40.     int32_t toEndLen = CIRCULAR_BUF_LEN - cb->eventsBuf_.writePosition; 
  41.     if (toEndLen == 0) { 
  42.             cb->eventsBuf_.circularBuf[0] = eventCopy; 
  43.             cb->eventsBuf_.writePosition = 1 - toEndLen; 
  44.     } else { 
  45.             cb->eventsBuf_.circularBuf[cb->eventsBuf_.writePosition] = eventCopy; 
  46.             cb->eventsBuf_.writePosition += 1; 
  47.     } 
  48.     …… 

至此,回过头来再看SensorDataProcesser::ProcessEvents,lock锁激活后,获取到eventsBuf_。

  1. int32_t SensorDataProcesser::ProcessEvents(sptr<ReportDataCallback>dataCallback) 
  2.     if (dataCallback == nullptr) { 
  3.         HiLog::Error(LABEL, "%{public}s dataCallback cannot be null", __func__); 
  4.         return INVALID_POINTER; 
  5.     } 
  6.     std::unique_lock<std::mutex> lk(SensorServiceImpl::dataMutex_); 
  7.     SensorServiceImpl::dataCondition_.wait(lk); 
  8.     auto &eventsBuf = dataCallback->GetEventData(); 
  9.     if (eventsBuf.eventNum <= 0) { 
  10.         HiLog::Error(LABEL, "%{public}s data cannot be empty", __func__); 
  11.         return NO_EVENT; 
  12.     } 
  13.     int32_t eventNum = eventsBuf.eventNum; 
  14.     for (int32_t i = 0; i < eventNum; i++) { 
  15.         // 通过EventFilter report eventsBuf数据 
  16.         EventFilter(eventsBuf); 
  17.         delete eventsBuf.circularBuf[eventsBuf.readPosition].data; 
  18.         eventsBuf.circularBuf[eventsBuf.readPosition].data = nullptr; 
  19.         eventsBuf.readPosition++; 
  20.         if (eventsBuf.readPosition == CIRCULAR_BUF_LEN) { 
  21.             eventsBuf.readPosition = 0; 
  22.         } 
  23.         eventsBuf.eventNum--; 
  24.     } 
  25.     return SUCCESS; 

EventFilter最终会调用SendRawData,通过该函数的channel->SendData,调用Socket send函数发送sensor数据。这里的sendFd_就是前面创建的。(中间的调用过程请看前面的时序图)

  1. int32_t SensorBasicDataChannel::SendData(const void *vaddr, size_t size
  2.     if (vaddr == nullptr || sendFd_ < 0) { 
  3.         HiLog::Error(LABEL, "%{public}s failed, param is invalid", __func__); 
  4.         return SENSOR_CHANNEL_SEND_ADDR_ERR; 
  5.     } 
  6.     ssize_t length; 
  7.     do { 
  8.         length = send(sendFd_, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL); 
  9.     } while (errno == EINTR); 
  10.     if (length < 0) { 
  11.         HiLog::Error(LABEL, "%{public}s send fail : %{public}d, length = %{public}d", __func__, errno, (int32_t)length); 
  12.         return SENSOR_CHANNEL_SEND_DATA_ERR; 
  13.     } 
  14.     return ERR_OK; 
  1. void MyFileDescriptorListener::OnReadable(int32_t fileDescriptor) 
  2.     if (fileDescriptor < 0) { 
  3.         HiLog::Error(LABEL, "%{public}s fileDescriptor: %{public}d", __func__, fileDescriptor); 
  4.         return
  5.     } 
  6.     FileDescriptorListener::OnReadable(fileDescriptor); 
  7.     struct TransferSensorEvents *receiveDataBuff_  
  8.         = new (std::nothrow) TransferSensorEvents[sizeof(struct TransferSensorEvents) * RECEIVE_DATA_SIZE]; 
  9.     // 接收sensor数据,这里的fileDescriptor就是receiveFd_ 
  10.     int32_t len = recv(fileDescriptor, receiveDataBuff_, sizeof(struct TransferSensorEvents) * RECEIVE_DATA_SIZE, NULL); 
  11.     while (len > 0) { 
  12.         int32_t eventSize = sizeof(struct TransferSensorEvents); 
  13.         int32_t num = len / eventSize; 
  14.         for (int i = 0; i < num; i++) { 
  15.             SensorEvent event = { 
  16.                 .sensorTypeId = receiveDataBuff_[i].sensorTypeId, 
  17.                 .version = receiveDataBuff_[i].version, 
  18.                 .timestamp = receiveDataBuff_[i].timestamp
  19.                 .option = receiveDataBuff_[i].option
  20.                 .mode = receiveDataBuff_[i].mode, 
  21.                 .dataLen = receiveDataBuff_[i].dataLen, 
  22.                 .data = receiveDataBuff_[i].data 
  23.             }; 
  24.             float *data = (float *)(event.data); 
  25.             // 通过dataCB_将数据再往上层传递,dataCB_即SensorAgentProxy::HandleSensorData 
  26.             channel_->dataCB_(&event, 1, channel_->privateData_); 
  27.         } 
  28.         len = recv(fileDescriptor, receiveDataBuff_, sizeof(struct TransferSensorEvents) * RECEIVE_DATA_SIZE, NULL); 
  29.     } 
  1. void SensorAgentProxy::HandleSensorData(struct SensorEvent *events, int32_t num, void *data) 
  2.     if (events == nullptr || num <= 0) { 
  3.         HiLog::Error(LABEL, "%{public}s events is null or num is invalid", __func__); 
  4.         return
  5.     } 
  6.     struct SensorEvent eventStream; 
  7.     for (int32_t i = 0; i < num; ++i) { 
  8.         eventStream = events[i]; 
  9.         if (eventStream.data == nullptr || g_subscribeMap[eventStream.sensorTypeId] == nullptr) { 
  10.             HiLog::Error(LABEL, "%{public}s data or sensorUser is nullptr", __func__); 
  11.             return
  12.         } 
  13.         if (g_subscribeMap.find(eventStream.sensorTypeId) == g_subscribeMap.end()) { 
  14.             HiLog::Error(LABEL, "%{public}s sensorTypeId not in g_subscribeMap", __func__); 
  15.             return
  16.         } 
  17.         // 这里的callback调用的是sensor_js.cpp DataCallbackImpl函数 
  18.         g_subscribeMap[eventStream.sensorTypeId]->callback(&eventStream); 
  19.     } 

通过DataCallbackImpl将数据上报给JS应用。以加速度计为例,会出现下面的log打印。

  1. sensor.on(sensor.SensorType.SENSOR_TYPE_ID_ACCELEROMETER, (error, data) => { 
  2. if (error) { 
  3.     console.error("Failed to subscribe to acceleration data. Error code: " + 
  4.     error.code + "; message: " + error.message); 
  5.     return
  6. console.info("Acceleration data obtained. x: " + data.x + "; y: " + data.y + ";z: " + data.z); 
  7. }, {'interval':200000000}); 

总结

本文主要和大家分享传感器应用到框架层的实现,重点分析了传感器订阅、启动以及接收订阅传感器数据,做了较为详细的代码说明,希望通过本文您能初步掌握JS应用开发到框架层开发的步骤与流程。关于传感器HDF框架和驱动的分析,请关注后续文章。

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2021-12-17 16:42:09

2022-07-05 16:03:29

电源管理子系统鸿蒙

2021-09-13 15:15:18

2022-06-13 14:18:39

电源管理子系统耗电量服务

2022-06-07 10:33:29

Camera组件鸿蒙

2022-07-27 14:30:15

分布式数据鸿蒙

2021-09-17 14:38:58

2022-02-17 20:57:07

OpenHarmon操作系统鸿蒙

2022-01-06 16:17:58

2022-05-11 15:08:52

驱动开发系统移植

2022-01-13 10:11:59

2021-11-18 10:28:03

2022-04-15 14:31:02

鸿蒙操作系统

2022-02-28 14:54:48

openHarmon鸿蒙操作系统

2021-12-14 14:45:38

2022-03-04 15:43:36

文件管理模块Harmony鸿蒙

2021-12-14 10:16:00

2021-11-10 16:10:18

2022-05-17 10:33:58

设备开发鸿蒙操作系统

2022-05-20 10:32:49

事件循环器事件队列鸿蒙

同话题下的热门内容

字节的前端监控 SDK 是怎样设计的TestOps完全手册:工作流、生命周期、团队和流程使用Python快速搭建接口自动化测试脚本实战总结你需要知道的TypeScript高级类型不要在 Python 中使用循环,这些方法其实更棒!哪种编程语言最适合开发网页抓取工具?从 Islands Architecture 看前端有多卷反应式JavaScript:前端架构的演变

编辑推荐

太厉害了,终于有人能把TCP/IP协议讲的明明白白了!牛人5次面试腾讯不成功的经验HBase原理–所有Region切分的细节都在这里了Javascript如何监听页面刷新和关闭事件如何搭建一个HTTPS服务端
我收藏的内容
点赞
收藏

51CTO技术栈公众号