1 /*
2  * Copyright (c) 2022 Chipsea Technologies (Shenzhen) Corp., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "medical_sensor_dump.h"
17 
18 #include <cinttypes>
19 #include <ctime>
20 #include <queue>
21 
22 #include "medical_log_domain.h"
23 #include "medical_errors.h"
24 
25 namespace OHOS {
26 namespace Sensors {
27 using namespace OHOS::HiviewDFX;
28 
29 enum class DumpDataSizeType {
30     PPG_DATA_SIZE = 400,
31     COMMON_DATA_SIZE = 1,
32 };
33 
34 namespace {
35 constexpr HiLogLabel LABEL = { LOG_CORE, MedicalSensorLogDomain::MEDICAL_SENSOR_SERVICE, "MedicalSensorDump" };
36 constexpr uint32_t MAX_DUMP_DATA_SIZE = 10;
37 constexpr uint32_t MS_NS = 1000000;
38 constexpr uint32_t PPG = 256;
39 constexpr int32_t MAX_DMUP_PARAM = 2;
40 }  // namespace
41 
42 std::unordered_map<uint32_t, std::string> MedicalSensorDump::sensorMap_ = {
43     { PPG, "PPG" },
44 };
45 
DumpSensorHelp(int32_t fd,const std::vector<std::u16string> & args)46 bool MedicalSensorDump::DumpSensorHelp(int32_t fd, const std::vector<std::u16string> &args)
47 {
48     if ((args.empty()) || (args[0].compare(u"-h") != 0)) {
49         HiLog::Error(LABEL, "%{public}s args cannot be empty or invalid", __func__);
50         return false;
51     }
52     DumpHelp(fd);
53     return true;
54 }
55 
DumpHelp(int32_t fd)56 void MedicalSensorDump::DumpHelp(int32_t fd)
57 {
58     dprintf(fd, "Usage:\n");
59     dprintf(fd, "      -h: dump help\n");
60     dprintf(fd, "      -l: dump the sensor list\n");
61     dprintf(fd, "      -c: dump the sensor data channel info\n");
62     dprintf(fd, "      -o: dump the opening sensors\n");
63     dprintf(fd, "      -d: dump the last 10 packages sensor data\n");
64 }
65 
DumpSensorList(int32_t fd,const std::vector<MedicalSensor> & sensors,const std::vector<std::u16string> & args)66 bool MedicalSensorDump::DumpSensorList(int32_t fd,
67     const std::vector<MedicalSensor> &sensors, const std::vector<std::u16string> &args)
68 {
69     if ((args.empty()) || (args[0].compare(u"-l") != 0)) {
70         HiLog::Error(LABEL, "%{public}s args cannot be empty or invalid", __func__);
71         return false;
72     }
73     DumpCurrentTime(fd);
74     dprintf(fd, "Total sensor:%d, MedicalSensor list:\n", int32_t { sensors.size() });
75     for (const auto &sensor : sensors) {
76         auto sensorId = sensor.GetSensorId();
77         dprintf(fd,
78                 "sensorId:%8u | sensorType:%s | name:%s | vendor:%s | maxRange:%f | fifoMaxEventCount:%d "
79                 "| minSamplePeriodNs:%lld | maxSamplePeriodNs:%lld\n",
80                 sensorId, sensorMap_[sensorId].c_str(), sensor.GetName().c_str(), sensor.GetVendor().c_str(),
81                 sensor.GetMaxRange(), sensor.GetFifoMaxEventCount(), (long long) { sensor.GetMinSamplePeriodNs() },
82                 (long long) { sensor.GetMaxSamplePeriodNs() });
83     }
84     return true;
85 }
86 
DumpSensorChannel(int32_t fd,ClientInfo & clientInfo,const std::vector<std::u16string> & args)87 bool MedicalSensorDump::DumpSensorChannel(int32_t fd, ClientInfo &clientInfo, const std::vector<std::u16string> &args)
88 {
89     if ((args.empty()) || (args[0].compare(u"-c") != 0)) {
90         HiLog::Error(LABEL, "%{public}s args cannot be empty or invalid", __func__);
91         return false;
92     }
93     DumpCurrentTime(fd);
94     dprintf(fd, "MedicalSensor channel info:\n");
95     std::vector<MedicalSensorChannelInfo> channelInfo;
96     clientInfo.GetSensorChannelInfo(channelInfo);
97     for (const auto &channel : channelInfo) {
98         auto sensorId = channel.GetSensorId();
99         std::string cmds("");
100         auto cmdList = channel.GetCmdType();
101         for (auto cmd : cmdList) {
102             cmds += (std::to_string(cmd) + " ");
103         }
104         dprintf(fd,
105                 "uid:%d | packageName:%s | sensorId:%8u | sensorType:%s | samplingPeriodNs:%d "
106                 "| fifoCount:%u | cmdType:%s\n",
107                 channel.GetUid(), channel.GetPackageName().c_str(), sensorId, sensorMap_[sensorId].c_str(),
108                 int32_t { channel.GetSamplingPeriodNs() }, channel.GetFifoCount(), cmds.c_str());
109     }
110     return true;
111 }
112 
DumpOpeningSensor(int32_t fd,const std::vector<MedicalSensor> & sensors,ClientInfo & clientInfo,const std::vector<std::u16string> & args)113 bool MedicalSensorDump::DumpOpeningSensor(int32_t fd, const std::vector<MedicalSensor> &sensors,
114     ClientInfo &clientInfo, const std::vector<std::u16string> &args)
115 {
116     if ((args.empty()) || (args[0].compare(u"-o") != 0)) {
117         HiLog::Error(LABEL, "%{public}s args cannot be empty or invalid", __func__);
118         return false;
119     }
120     DumpCurrentTime(fd);
121     dprintf(fd, "Opening sensors:\n");
122     for (const auto &sensor : sensors) {
123         uint32_t sensorId = sensor.GetSensorId();
124         if (clientInfo.GetSensorState(sensorId) == SENSOR_ENABLED) {
125             dprintf(fd, "sensorId: %8u | sensorType: %s\n", sensorId, sensorMap_[sensorId].c_str());
126         }
127     }
128     return true;
129 }
130 
DumpSensorData(int32_t fd,ClientInfo & clientInfo,const std::vector<std::u16string> & args)131 bool MedicalSensorDump::DumpSensorData(int32_t fd, ClientInfo &clientInfo, const std::vector<std::u16string> &args)
132 {
133     if ((args.empty()) || (args[0].compare(u"-d") != 0)) {
134         HiLog::Error(LABEL, "%{public}s args cannot be empty or invalid", __func__);
135         return false;
136     }
137     dprintf(fd, "Last 10 packages sensor data:\n");
138     auto dataMap = clientInfo.GetDataQueue();
139     int32_t j = 0;
140     for (auto &sensorData : dataMap) {
141         uint32_t sensorId = sensorData.first;
142         dprintf(fd, "sensorId: %8u | sensorType: %s:\n", sensorId, sensorMap_[sensorId].c_str());
143         for (uint32_t i = 0; i < MAX_DUMP_DATA_SIZE && (!sensorData.second.empty()); i++) {
144             auto data = sensorData.second.front();
145             sensorData.second.pop();
146             timespec time = { 0, 0 };
147             tm *timeinfo = localtime(&(time.tv_sec));
148             if (timeinfo == nullptr) {
149                 HiLog::Error(LABEL, "%{public}s timeinfo cannot be null", __func__);
150                 return false;
151             }
152             dprintf(fd, "      %2d (ts=%.9f, time=%02d:%02d:%02d.%03d) | data:%s", ++j, data.timestamp / 1e9,
153                     timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, int32_t { (time.tv_nsec / MS_NS) },
154                     GetDataBySensorId(sensorId, data).c_str());
155         }
156     }
157     return true;
158 }
159 
DumpCurrentTime(int32_t fd)160 void MedicalSensorDump::DumpCurrentTime(int32_t fd)
161 {
162     timespec curTime = { 0, 0 };
163     clock_gettime(CLOCK_REALTIME, &curTime);
164     tm *timeinfo = localtime(&(curTime.tv_sec));
165     if (timeinfo == nullptr) {
166         HiLog::Error(LABEL, "%{public}s timeinfo cannot be null", __func__);
167         return;
168     }
169     dprintf(fd, "Current time: %02d:%02d:%02d.%03d\n", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec,
170             int32_t { (curTime.tv_nsec / MS_NS) });
171 }
172 
DataSizeBySensorId(uint32_t sensorId)173 int32_t MedicalSensorDump::DataSizeBySensorId(uint32_t sensorId)
174 {
175     switch (sensorId) {
176         case PPG:
177             return static_cast<int32_t>(DumpDataSizeType::PPG_DATA_SIZE);
178         default:
179             return static_cast<int32_t>(DumpDataSizeType::COMMON_DATA_SIZE);
180     }
181 }
182 
GetDataBySensorId(uint32_t sensorId,struct SensorEvent & sensorData)183 std::string MedicalSensorDump::GetDataBySensorId(uint32_t sensorId, struct SensorEvent &sensorData)
184 {
185     HiLog::Debug(LABEL, "%{public}s sensorId: %{public}u", __func__, sensorId);
186     std::string buffer;
187     int32_t dataLen = DataSizeBySensorId(sensorId);
188     for (int32_t i = 0; i < dataLen; ++i) {
189         buffer.append(std::to_string(sensorData.data[i])).append(",");
190     }
191     buffer.append("\n");
192     return buffer;
193 }
194 
Dump(int32_t fd,const std::vector<std::u16string> & args,std::vector<MedicalSensor> & sensors,ClientInfo & clientInfo)195 int32_t MedicalSensorDump::Dump(int32_t fd, const std::vector<std::u16string> &args,
196     std::vector<MedicalSensor> &sensors, ClientInfo &clientInfo)
197 {
198     HiLog::Info(LABEL, "%{public}s begin", __func__);
199 
200     if ((args.empty()) || (args[0].size() != MAX_DMUP_PARAM)) {
201         HiLog::Error(LABEL, "%{public}s param cannot be empty or the length is not 2", __func__);
202         dprintf(fd, "cmd param number is not equal to 2\n");
203         DumpHelp(fd);
204         return DUMP_PARAM_ERR;
205     }
206     bool helpRet = DumpSensorHelp(fd, args);
207     bool listRet = DumpSensorList(fd, sensors, args);
208     bool channelRet = DumpSensorChannel(fd, clientInfo, args);
209     bool openRet = DumpOpeningSensor(fd, sensors, clientInfo, args);
210     bool dataRet = DumpSensorData(fd, clientInfo, args);
211     bool total = helpRet + listRet + channelRet + openRet + dataRet;
212     if (!total) {
213         dprintf(fd, "cmd param is error\n");
214         DumpHelp(fd);
215         return DUMP_PARAM_ERR;
216     }
217     HiLog::Info(LABEL, "%{public}s end", __func__);
218     return ERR_OK;
219 }
220 }  // namespace Sensors
221 }  // namespace OHOS
222