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 #include "medical_js.h"
16 
17 #include <cstdio>
18 #include <cstdlib>
19 #include <cstring>
20 #include <map>
21 #include <pthread.h>
22 #include <string>
23 #include <thread>
24 #include <unistd.h>
25 
26 #include "hilog/log.h"
27 #include "napi/native_api.h"
28 #include "napi/native_node_api.h"
29 #include "medical_native_impl.h"
30 #include "medical_napi_utils.h"
31 
32 #include "refbase.h"
33 #include "securec.h"
34 
35 namespace OHOS {
36 namespace Sensors {
37 using namespace OHOS::HiviewDFX;
38 static constexpr HiLogLabel LABEL = {LOG_CORE, 0xD002786, "AfeJsAPI"};
39 
40 static std::map<int32_t, struct AsyncCallbackInfo*> g_onCallbackInfos;
41 
DataCallbackImpl(SensorEvent * event)42 static void DataCallbackImpl(SensorEvent *event)
43 {
44     HiLog::Info(LABEL, "%{public}s in", __func__);
45     if (event == nullptr) {
46         HiLog::Error(LABEL, "%{public}s event is null!", __func__);
47         return;
48     }
49     int32_t sensorTypeId = event->sensorTypeId;
50     uint32_t *data = (uint32_t *)(event->data);
51     uint32_t maxDataLen = MAX_DATA_LEN * sizeof(uint32_t);
52     uint32_t dataLen = (event->dataLen > maxDataLen) ? maxDataLen : event->dataLen;
53     // check sensorType
54     if (g_onCallbackInfos.find(sensorTypeId) == g_onCallbackInfos.end()) {
55         HiLog::Debug(LABEL, "%{public}s no subscribe to the sensor data on", __func__);
56         return;
57     }
58     AsyncCallbackInfo *onCallbackInfo = g_onCallbackInfos[sensorTypeId];
59     onCallbackInfo->sensorTypeId = sensorTypeId;
60     onCallbackInfo->sensorDataLength = dataLen / sizeof(uint32_t);
61     if (memcpy_s(onCallbackInfo->sensorData, dataLen, data, dataLen) != EOK) {
62         HiLog::Error(LABEL, "%{public}s copy data failed", __func__);
63         return;
64     }
65 
66     EmitUvEventLoop(static_cast <AsyncCallbackInfo *> (onCallbackInfo));
67     HiLog::Info(LABEL, "%{public}s end", __func__);
68 }
69 
70 static const MedicalSensorUser user = {
71     .callback = DataCallbackImpl
72 };
73 
UnsubscribeSensor(int32_t sensorTypeId)74 static int32_t UnsubscribeSensor(int32_t sensorTypeId)
75 {
76     HiLog::Info(LABEL, "%{public}s in", __func__);
77     int32_t ret = DeactivateSensor(sensorTypeId, &user);
78     if (ret < 0) {
79         HiLog::Error(LABEL, "%{public}s  DeactivateSensor failed", __func__);
80         return ret;
81     }
82     ret = UnsubscribeSensor(sensorTypeId, &user);
83     if (ret < 0) {
84         HiLog::Error(LABEL, "%{public}s  UnsubscribeSensor failed", __func__);
85         return ret;
86     }
87     HiLog::Info(LABEL, "%{public}s left", __func__);
88     return 0;
89 }
90 
SubscribeSensor(int32_t sensorTypeId,int64_t interval,const MedicalSensorUser * user)91 static int32_t SubscribeSensor(int32_t sensorTypeId, int64_t interval, const MedicalSensorUser *user)
92 {
93     HiLog::Info(LABEL, "%{public}s in, sensorTypeId: %{public}d", __func__, sensorTypeId);
94     int32_t ret = SubscribeSensor(sensorTypeId, user);
95     if (ret < 0) {
96         HiLog::Error(LABEL, "%{public}s subscribeSensor failed", __func__);
97         return ret;
98     }
99     ret = SetBatch(sensorTypeId, user, interval, 0);
100     if (ret < 0) {
101         HiLog::Error(LABEL, "%{public}s set batch failed", __func__);
102         return ret;
103     }
104     ret = ActivateSensor(sensorTypeId, user);
105     if (ret < 0) {
106         HiLog::Error(LABEL, "%{public}s activateSensor failed", __func__);
107         return ret;
108     }
109     return 0;
110 }
111 
On(napi_env env,napi_callback_info info)112 static napi_value On(napi_env env, napi_callback_info info)
113 {
114     HiLog::Info(LABEL, "%{public}s in", __func__);
115     size_t requiredMaxArgc = 3;
116     size_t requiredMinArgc = 2;
117     size_t argc = 3;
118     napi_value args[3];
119     napi_value thisVar;
120     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisVar, NULL));
121     NAPI_ASSERT(env, ((argc >= requiredMinArgc) && (argc <= requiredMaxArgc)), "requires 2 or 3 parameteres");
122 
123     napi_valuetype eventId = napi_undefined;
124     napi_typeof(env, args[0], &eventId);
125     NAPI_ASSERT(env, eventId == napi_number, "type mismatch for parameter 1");
126     int32_t sensorTypeId = GetCppInt32(args[0], env);
127 
128     napi_valuetype handler = napi_undefined;
129     napi_typeof(env, args[1], &handler);
130     NAPI_ASSERT(env, handler == napi_function, "type mismatch for parameter 2");
131 
132     int64_t interval = 200000000;
133     if (argc == requiredMaxArgc) {
134         HiLog::Info(LABEL, "%{public}s argc = 3!", __func__);
135         napi_value value = NapiGetNamedProperty(args[2], "interval", env);
136         napi_valuetype intervalType = napi_undefined;
137         napi_typeof(env, value, &intervalType);
138         NAPI_ASSERT(env, intervalType == napi_number, "type mismatch for parameter 3");
139         interval = GetCppInt64(value, env);
140     }
141     AsyncCallbackInfo *asyncCallbackInfo = new AsyncCallbackInfo {
142         .env = env,
143         .asyncWork = nullptr,
144         .deferred = nullptr,
145     };
146     napi_create_reference(env, args[1], 1, &asyncCallbackInfo->callback[0]);
147     g_onCallbackInfos[sensorTypeId] = asyncCallbackInfo;
148     int32_t ret = SubscribeSensor(sensorTypeId, interval, &user);
149     if (ret < 0) {
150         HiLog::Error(LABEL, "%{public}s subscribeSensor failed", __func__);
151         EmitAsyncCallbackWork(asyncCallbackInfo);
152         g_onCallbackInfos.erase(sensorTypeId);
153         return nullptr;
154     }
155     HiLog::Info(LABEL, "%{public}s out", __func__);
156     return nullptr;
157 }
158 
Off(napi_env env,napi_callback_info info)159 static napi_value Off(napi_env env, napi_callback_info info)
160 {
161     HiLog::Info(LABEL, "%{public}s in", __func__);
162     size_t argc = 2;
163     size_t requiredMaxArgc = 2;
164     size_t requiredMinArgc = 1;
165     napi_value args[2];
166     napi_value thisVar;
167     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisVar, NULL));
168     NAPI_ASSERT(env, ((argc >= requiredMinArgc) && (argc <= requiredMaxArgc)), "requires 1 or 2 parameteres");
169 
170     napi_valuetype eventId = napi_undefined;
171     napi_typeof(env, args[0], &eventId);
172     NAPI_ASSERT(env, eventId == napi_number, "type mismatch for parameter 1");
173     int32_t sensorTypeId = GetCppInt32(args[0], env);
174 
175     AsyncCallbackInfo *asyncCallbackInfo = new AsyncCallbackInfo {
176         .env = env,
177         .asyncWork = nullptr,
178         .deferred = nullptr,
179     };
180 
181     if (argc == requiredMaxArgc) {
182         napi_valuetype handler = napi_undefined;
183         napi_typeof(env, args[1], &handler);
184         NAPI_ASSERT(env, handler == napi_function, "type mismatch for parameter 2");
185     } else {
186         NAPI_ASSERT(env, g_onCallbackInfos.find(sensorTypeId) != g_onCallbackInfos.end(), "no callback registered");
187         napi_get_reference_value(env, g_onCallbackInfos[sensorTypeId]->callback[0], &args[1]);
188     }
189     napi_create_reference(env, args[1], 1, &asyncCallbackInfo->callback[0]);
190 
191     int32_t ret = UnsubscribeSensor(sensorTypeId);
192     if (ret < 0) {
193         HiLog::Error(LABEL, "%{public}s UnsubscribeSensor failed", __func__);
194     } else {
195         HiLog::Error(LABEL, "%{public}s UnsubscribeSensor success", __func__);
196         if (g_onCallbackInfos.find(sensorTypeId) != g_onCallbackInfos.end()) {
197             napi_delete_reference(env, g_onCallbackInfos[sensorTypeId]->callback[0]);
198             delete g_onCallbackInfos[sensorTypeId];
199             g_onCallbackInfos[sensorTypeId] = nullptr;
200             g_onCallbackInfos.erase(sensorTypeId);
201         }
202     }
203     EmitAsyncCallbackWork(asyncCallbackInfo);
204     HiLog::Info(LABEL, "%{public}s left", __func__);
205     return nullptr;
206 }
207 
SetOpt(napi_env env,napi_callback_info info)208 static napi_value SetOpt(napi_env env, napi_callback_info info)
209 {
210     HiLog::Info(LABEL, "%{public}s in", __func__);
211     size_t argc = 2;
212     napi_value args[2];
213     napi_value thisVar;
214     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisVar, NULL));
215 
216     if (argc < 1) {
217         HiLog::Error(LABEL, "%{public}s Invalid input.", __func__);
218         return nullptr;
219     }
220     if (!IsMatchType(args[0], napi_number, env)) {
221         HiLog::Error(LABEL, "%{public}s argument should be number type!", __func__);
222         return nullptr;
223     }
224     int32_t sensorTypeId = GetCppInt32(args[0], env);
225 
226     if (!IsMatchType(args[1], napi_number, env)) {
227         HiLog::Error(LABEL, "%{public}s argument should be function type!", __func__);
228         return nullptr;
229     }
230     int32_t opt = GetCppInt32(args[1], env);
231 
232     int32_t ret = SetOption(sensorTypeId, &user, opt);
233     if (ret < 0) {
234         HiLog::Error(LABEL, "%{public}s SetOption failed", __func__);
235     } else {
236         HiLog::Error(LABEL, "%{public}s SetOption success", __func__);
237     }
238     HiLog::Info(LABEL, "%{public}s left", __func__);
239     return nullptr;
240 }
241 
EnumClassConstructor(napi_env env,napi_callback_info info)242 static napi_value EnumClassConstructor(napi_env env, napi_callback_info info)
243 {
244     size_t argc = 0;
245     napi_value args[1] = {0};
246     napi_value res = nullptr;
247     void *data = nullptr;
248     napi_status status = napi_get_cb_info(env, info, &argc, args, &res, &data);
249     if (status != napi_ok) {
250         return nullptr;
251     }
252     return res;
253 }
254 
CreateEnumMdicalSensorType(napi_env env,napi_value exports)255 static napi_value CreateEnumMdicalSensorType(napi_env env, napi_value exports)
256 {
257     napi_property_descriptor desc[] = {
258         DECLARE_NAPI_STATIC_PROPERTY("TYPE_ID_PHOTOPLETHYSMOGRAPH", GetNapiInt32(TYPE_ID_PHOTOPLETHYSMOGRAPH, env)),
259     };
260     napi_value result = nullptr;
261     napi_define_class(env, "MedicalSensorType", NAPI_AUTO_LENGTH, EnumClassConstructor, nullptr,
262         sizeof(desc) / sizeof(*desc), desc, &result);
263     napi_set_named_property(env, exports, "MedicalSensorType", result);
264     return exports;
265 }
266 
267 EXTERN_C_START
268 
Init(napi_env env,napi_value exports)269 static napi_value Init(napi_env env, napi_value exports)
270 {
271     napi_property_descriptor desc[] = {
272         DECLARE_NAPI_FUNCTION("on", On),
273         DECLARE_NAPI_FUNCTION("setOpt", SetOpt),
274         DECLARE_NAPI_FUNCTION("off", Off)
275     };
276     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc));
277     CreateEnumMdicalSensorType(env, exports);
278     return exports;
279 }
280 EXTERN_C_END
281 
282 static napi_module _module = {
283     .nm_version = 1,
284     .nm_flags = 0,
285     .nm_filename = NULL,
286     .nm_register_func = Init,
287     .nm_modname = "medical",
288     .nm_priv = ((void *)0),
289     .reserved = {0}
290 };
291 
RegisterModule(void)292 extern "C" __attribute__((constructor)) void RegisterModule(void)
293 {
294     napi_module_register(&_module);
295 }
296 } // namespace Sensors
297 } // namespace OHOS
298