67ece496df5becc06b24bb4e806b436636c289c8
[platform/upstream/iotjs.git] / tools / src / module / iotjs_module_pwm.c
1 /* Copyright 2016-present Samsung Electronics Co., Ltd. and other contributors
2  *
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 "iotjs_def.h"
17 #include "iotjs_module_pwm.h"
18 #include "iotjs_objectwrap.h"
19
20
21 static void iotjs_pwm_destroy(iotjs_pwm_t* pwm);
22 static iotjs_pwm_t* iotjs_pwm_instance_from_jval(const iotjs_jval_t* jpwm);
23
24
25 static iotjs_pwm_t* iotjs_pwm_create(const iotjs_jval_t* jpwm) {
26   iotjs_pwm_t* pwm = IOTJS_ALLOC(iotjs_pwm_t);
27   IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_pwm_t, pwm);
28   iotjs_jobjectwrap_initialize(&_this->jobjectwrap, jpwm,
29                                (JFreeHandlerType)iotjs_pwm_destroy);
30
31   _this->period = -1;
32   _this->duty_cycle = 0;
33 #if defined(__NUTTX__)
34   _this->device_fd = -1;
35 #endif
36   return pwm;
37 }
38
39
40 static void iotjs_pwm_destroy(iotjs_pwm_t* pwm) {
41   IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_pwm_t, pwm);
42   iotjs_jobjectwrap_destroy(&_this->jobjectwrap);
43 #if defined(__linux__)
44   iotjs_string_destroy(&_this->device);
45 #endif
46   IOTJS_RELEASE(pwm);
47 }
48
49
50 #define THIS iotjs_pwm_reqwrap_t* pwm_reqwrap
51
52
53 static iotjs_pwm_reqwrap_t* iotjs_pwm_reqwrap_create(
54     const iotjs_jval_t* jcallback, const iotjs_jval_t* jpwm, PwmOp op) {
55   iotjs_pwm_reqwrap_t* pwm_reqwrap = IOTJS_ALLOC(iotjs_pwm_reqwrap_t);
56   IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_pwm_reqwrap_t, pwm_reqwrap);
57
58   iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req);
59
60   _this->req_data.op = op;
61   _this->pwm_instance = iotjs_pwm_instance_from_jval(jpwm);
62   _this->req_data.caller = NULL;
63
64   return pwm_reqwrap;
65 }
66
67
68 static void iotjs_pwm_reqwrap_destroy(THIS) {
69   IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_pwm_reqwrap_t, pwm_reqwrap);
70   iotjs_reqwrap_destroy(&_this->reqwrap);
71   IOTJS_RELEASE(pwm_reqwrap);
72 }
73
74
75 static void iotjs_pwm_reqwrap_dispatched(THIS) {
76   IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_pwm_reqwrap_t, pwm_reqwrap);
77   iotjs_pwm_reqwrap_destroy(pwm_reqwrap);
78 }
79
80
81 static uv_work_t* iotjs_pwm_reqwrap_req(THIS) {
82   IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_reqwrap_t, pwm_reqwrap);
83   return &_this->req;
84 }
85
86
87 static const iotjs_jval_t* iotjs_pwm_reqwrap_jcallback(THIS) {
88   IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_reqwrap_t, pwm_reqwrap);
89   return iotjs_reqwrap_jcallback(&_this->reqwrap);
90 }
91
92
93 static iotjs_pwm_t* iotjs_pwm_instance_from_jval(const iotjs_jval_t* jpwm) {
94   uintptr_t handle = iotjs_jval_get_object_native_handle(jpwm);
95   return (iotjs_pwm_t*)handle;
96 }
97
98
99 iotjs_pwm_reqwrap_t* iotjs_pwm_reqwrap_from_request(uv_work_t* req) {
100   return (iotjs_pwm_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)req));
101 }
102
103
104 iotjs_pwm_reqdata_t* iotjs_pwm_reqwrap_data(THIS) {
105   IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_reqwrap_t, pwm_reqwrap);
106   return &_this->req_data;
107 }
108
109
110 iotjs_pwm_t* iotjs_pwm_instance_from_reqwrap(THIS) {
111   IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_reqwrap_t, pwm_reqwrap);
112   return _this->pwm_instance;
113 }
114
115
116 static void iotjs_pwm_set_configuration(const iotjs_jval_t* jconfiguration,
117                                         iotjs_pwm_t* pwm) {
118   IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm);
119
120   iotjs_jval_t jpin =
121       iotjs_jval_get_property(jconfiguration, IOTJS_MAGIC_STRING_PIN);
122   _this->pin = iotjs_jval_as_number(&jpin);
123
124 #if defined(__linux__)
125   iotjs_jval_t jchip =
126       iotjs_jval_get_property(jconfiguration, IOTJS_MAGIC_STRING_CHIP);
127   _this->chip = iotjs_jval_as_number(&jchip);
128   iotjs_jval_destroy(&jchip);
129 #endif
130
131   iotjs_jval_t jperiod =
132       iotjs_jval_get_property(jconfiguration, IOTJS_MAGIC_STRING_PERIOD);
133   if (iotjs_jval_is_number(&jperiod))
134     _this->period = iotjs_jval_as_number(&jperiod);
135
136   iotjs_jval_t jduty_cycle =
137       iotjs_jval_get_property(jconfiguration, IOTJS_MAGIC_STRING_DUTYCYCLE);
138   if (iotjs_jval_is_number(&jduty_cycle))
139     _this->duty_cycle = iotjs_jval_as_number(&jduty_cycle);
140
141   iotjs_jval_destroy(&jpin);
142   iotjs_jval_destroy(&jperiod);
143   iotjs_jval_destroy(&jduty_cycle);
144 }
145
146 #undef THIS
147
148
149 static void iotjs_pwm_common_worker(uv_work_t* work_req) {
150   PWM_WORKER_INIT;
151
152   IOTJS_ASSERT(req_data->caller != NULL);
153
154   if (!req_data->caller(pwm)) {
155     req_data->result = false;
156     return;
157   }
158
159   req_data->result = true;
160 }
161
162
163 static void iotjs_pwm_after_worker(uv_work_t* work_req, int status) {
164   iotjs_pwm_reqwrap_t* req_wrap = iotjs_pwm_reqwrap_from_request(work_req);
165   iotjs_pwm_reqdata_t* req_data = iotjs_pwm_reqwrap_data(req_wrap);
166   iotjs_jargs_t jargs = iotjs_jargs_create(1);
167   bool result = req_data->result;
168
169   if (status) {
170     iotjs_jval_t error = iotjs_jval_create_error("System error");
171     iotjs_jargs_append_jval(&jargs, &error);
172     iotjs_jval_destroy(&error);
173   } else {
174     switch (req_data->op) {
175       case kPwmOpOpen:
176         if (!result) {
177           iotjs_jargs_append_error(&jargs, "Failed to open PWM device");
178         } else {
179           iotjs_jargs_append_null(&jargs);
180         }
181         break;
182       case kPwmOpSetDutyCycle:
183         if (!result) {
184           iotjs_jargs_append_error(&jargs, "Failed to set duty-cycle");
185         } else {
186           iotjs_jargs_append_null(&jargs);
187         }
188         break;
189       case kPwmOpSetPeriod:
190         if (!result) {
191           iotjs_jargs_append_error(&jargs, "Failed to set period");
192         } else {
193           iotjs_jargs_append_null(&jargs);
194         }
195         break;
196       case kPwmOpSetEnable:
197         if (!result) {
198           iotjs_jargs_append_error(&jargs, "Failed to set enable");
199         } else {
200           iotjs_jargs_append_null(&jargs);
201         }
202         break;
203       case kPwmOpClose:
204         if (!result) {
205           iotjs_jargs_append_error(&jargs, "Cannot close PWM device");
206         } else {
207           iotjs_jargs_append_null(&jargs);
208         }
209         break;
210       default: {
211         IOTJS_ASSERT(!"Unreachable");
212         break;
213       }
214     }
215   }
216
217   const iotjs_jval_t* jcallback = iotjs_pwm_reqwrap_jcallback(req_wrap);
218   iotjs_make_callback(jcallback, iotjs_jval_get_undefined(), &jargs);
219
220   iotjs_jargs_destroy(&jargs);
221
222   iotjs_pwm_reqwrap_dispatched(req_wrap);
223 }
224
225
226 #define PWM_ASYNC(call, jthis, jcallback, op)                          \
227   do {                                                                 \
228     uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); \
229     iotjs_pwm_reqwrap_t* req_wrap =                                    \
230         iotjs_pwm_reqwrap_create(jcallback, jthis, op);                \
231     uv_work_t* req = iotjs_pwm_reqwrap_req(req_wrap);                  \
232     uv_queue_work(loop, req, iotjs_pwm_##call##_worker,                \
233                   iotjs_pwm_after_worker);                             \
234   } while (0)
235
236
237 #define PWM_ASYNC_COMMON_WORKER(call, jthis, jcallback, op)                    \
238   do {                                                                         \
239     uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get());         \
240     iotjs_pwm_reqwrap_t* req_wrap =                                            \
241         iotjs_pwm_reqwrap_create(jcallback, jthis, op);                        \
242     uv_work_t* req = iotjs_pwm_reqwrap_req(req_wrap);                          \
243     iotjs_pwm_reqdata_t* req_data = iotjs_pwm_reqwrap_data(req_wrap);          \
244     req_data->caller = call;                                                   \
245     uv_queue_work(loop, req, iotjs_pwm_common_worker, iotjs_pwm_after_worker); \
246   } while (0)
247
248
249 JHANDLER_FUNCTION(PWMConstructor) {
250   JHANDLER_CHECK_THIS(object);
251   JHANDLER_CHECK_ARGS(2, object, function);
252
253   // Create PWM object
254   const iotjs_jval_t* jpwm = JHANDLER_GET_THIS(object);
255   iotjs_pwm_t* pwm = iotjs_pwm_create(jpwm);
256   IOTJS_ASSERT(pwm == iotjs_pwm_instance_from_jval(jpwm));
257
258   const iotjs_jval_t* jconfiguration = JHANDLER_GET_ARG(0, object);
259   const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(1, function);
260
261   // Set configuration
262   iotjs_pwm_set_configuration(jconfiguration, pwm);
263
264   PWM_ASYNC(open, jpwm, jcallback, kPwmOpOpen);
265 }
266
267
268 JHANDLER_FUNCTION(SetPeriod) {
269   JHANDLER_CHECK_ARGS(1, number);
270   JHANDLER_CHECK_ARG_IF_EXIST(1, function);
271
272   const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(1, function);
273   const iotjs_jval_t* jpwm = JHANDLER_GET_THIS(object);
274   iotjs_pwm_t* pwm = iotjs_pwm_instance_from_jval(jpwm);
275
276   IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm);
277   _this->period = JHANDLER_GET_ARG(0, number);
278
279   if (jcallback) {
280     PWM_ASYNC_COMMON_WORKER(iotjs_pwm_set_period, jpwm, jcallback,
281                             kPwmOpSetPeriod);
282   } else {
283     if (!iotjs_pwm_set_period(pwm)) {
284       JHANDLER_THROW(COMMON, "PWM SetPeriod Error");
285     }
286   }
287
288   iotjs_jhandler_return_null(jhandler);
289 }
290
291
292 JHANDLER_FUNCTION(SetDutyCycle) {
293   JHANDLER_CHECK_ARGS(1, number);
294   JHANDLER_CHECK_ARG_IF_EXIST(1, function);
295
296   const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(1, function);
297   const iotjs_jval_t* jpwm = JHANDLER_GET_THIS(object);
298   iotjs_pwm_t* pwm = iotjs_pwm_instance_from_jval(jpwm);
299
300   IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm);
301   _this->duty_cycle = JHANDLER_GET_ARG(0, number);
302
303   if (jcallback) {
304     PWM_ASYNC_COMMON_WORKER(iotjs_pwm_set_dutycycle, jpwm, jcallback,
305                             kPwmOpSetDutyCycle);
306   } else {
307     if (!iotjs_pwm_set_dutycycle(pwm)) {
308       JHANDLER_THROW(COMMON, "PWM SetDutyCycle Error");
309     }
310   }
311
312   iotjs_jhandler_return_null(jhandler);
313 }
314
315
316 JHANDLER_FUNCTION(SetEnable) {
317   JHANDLER_CHECK_ARGS(1, boolean);
318   JHANDLER_CHECK_ARG_IF_EXIST(1, function);
319
320   const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(1, function);
321   const iotjs_jval_t* jpwm = JHANDLER_GET_THIS(object);
322   iotjs_pwm_t* pwm = iotjs_pwm_instance_from_jval(jpwm);
323
324   IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm);
325   _this->enable = JHANDLER_GET_ARG(0, boolean);
326
327   if (jcallback) {
328     PWM_ASYNC_COMMON_WORKER(iotjs_pwm_set_enable, jpwm, jcallback,
329                             kPwmOpSetEnable);
330   } else {
331     if (!iotjs_pwm_set_enable(pwm)) {
332       JHANDLER_THROW(COMMON, "PWM SetEnabe Error");
333     }
334   }
335
336   iotjs_jhandler_return_null(jhandler);
337 }
338
339
340 JHANDLER_FUNCTION(Close) {
341   JHANDLER_CHECK_THIS(object);
342   JHANDLER_CHECK_ARG_IF_EXIST(0, function);
343
344   const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(0, function);
345   const iotjs_jval_t* jpwm = JHANDLER_GET_THIS(object);
346   iotjs_pwm_t* pwm = iotjs_pwm_instance_from_jval(jpwm);
347
348   if (jcallback) {
349     PWM_ASYNC_COMMON_WORKER(iotjs_pwm_close, jpwm, jcallback, kPwmOpClose);
350   } else {
351     if (!iotjs_pwm_close(pwm)) {
352       JHANDLER_THROW(COMMON, "PWM Close Error");
353     }
354   }
355
356   iotjs_jhandler_return_null(jhandler);
357 }
358
359
360 iotjs_jval_t InitPwm() {
361   iotjs_jval_t jpwm_constructor =
362       iotjs_jval_create_function_with_dispatch(PWMConstructor);
363
364   iotjs_jval_t jprototype = iotjs_jval_create_object();
365
366   iotjs_jval_set_method(&jprototype, IOTJS_MAGIC_STRING_SETPERIOD, SetPeriod);
367   iotjs_jval_set_method(&jprototype, IOTJS_MAGIC_STRING_SETDUTYCYCLE,
368                         SetDutyCycle);
369   iotjs_jval_set_method(&jprototype, IOTJS_MAGIC_STRING_SETENABLE, SetEnable);
370   iotjs_jval_set_method(&jprototype, IOTJS_MAGIC_STRING_CLOSE, Close);
371
372   iotjs_jval_set_property_jval(&jpwm_constructor, IOTJS_MAGIC_STRING_PROTOTYPE,
373                                &jprototype);
374
375   iotjs_jval_destroy(&jprototype);
376
377   return jpwm_constructor;
378 }