3a49a9ad66b640d83b34c56f17e9892ea0847a3f
[platform/upstream/iotjs.git] / src / module / iotjs_module_i2c.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
17 #include "iotjs_def.h"
18 #include "iotjs_module_i2c.h"
19 #include "iotjs_objectwrap.h"
20
21
22 #define THIS iotjs_i2c_reqwrap_t* i2c_reqwrap
23
24
25 iotjs_i2c_reqwrap_t* iotjs_i2c_reqwrap_create(const iotjs_jval_t* jcallback,
26                                               const iotjs_jval_t* ji2c,
27                                               I2cOp op) {
28   iotjs_i2c_reqwrap_t* i2c_reqwrap = IOTJS_ALLOC(iotjs_i2c_reqwrap_t);
29   IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_i2c_reqwrap_t, i2c_reqwrap);
30
31   iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req);
32
33   _this->req_data.op = op;
34 #if defined(__linux__) || defined(__APPLE__)
35   _this->req_data.device = iotjs_string_create("");
36 #endif
37   _this->i2c_data = iotjs_i2c_instance_from_jval(ji2c);
38   return i2c_reqwrap;
39 }
40
41
42 static void iotjs_i2c_reqwrap_destroy(THIS) {
43   IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_i2c_reqwrap_t, i2c_reqwrap);
44   iotjs_reqwrap_destroy(&_this->reqwrap);
45 #if defined(__linux__) || defined(__APPLE__)
46   iotjs_string_destroy(&_this->req_data.device);
47 #endif
48   IOTJS_RELEASE(i2c_reqwrap);
49 }
50
51
52 void iotjs_i2c_reqwrap_dispatched(THIS) {
53   IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_i2c_reqwrap_t, i2c_reqwrap);
54   iotjs_i2c_reqwrap_destroy(i2c_reqwrap);
55 }
56
57
58 uv_work_t* iotjs_i2c_reqwrap_req(THIS) {
59   IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_reqwrap_t, i2c_reqwrap);
60   return &_this->req;
61 }
62
63
64 const iotjs_jval_t* iotjs_i2c_reqwrap_jcallback(THIS) {
65   IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_reqwrap_t, i2c_reqwrap);
66   return iotjs_reqwrap_jcallback(&_this->reqwrap);
67 }
68
69
70 iotjs_i2c_reqwrap_t* iotjs_i2c_reqwrap_from_request(uv_work_t* req) {
71   return (iotjs_i2c_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)req));
72 }
73
74
75 iotjs_i2c_reqdata_t* iotjs_i2c_reqwrap_data(THIS) {
76   IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_reqwrap_t, i2c_reqwrap);
77   return &_this->req_data;
78 }
79
80
81 iotjs_i2c_t* iotjs_i2c_instance_from_reqwrap(THIS) {
82   IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_reqwrap_t, i2c_reqwrap);
83   return _this->i2c_data;
84 }
85
86 #undef THIS
87
88
89 static void iotjs_i2c_destroy(iotjs_i2c_t* i2c);
90
91
92 iotjs_i2c_t* iotjs_i2c_create(const iotjs_jval_t* ji2c) {
93   iotjs_i2c_t* i2c = IOTJS_ALLOC(iotjs_i2c_t);
94   IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_i2c_t, i2c);
95
96 #if defined(__NUTTX__)
97   _this->i2c_master = NULL;
98 #endif
99
100   iotjs_jobjectwrap_initialize(&_this->jobjectwrap, ji2c,
101                                (JFreeHandlerType)iotjs_i2c_destroy);
102   return i2c;
103 }
104
105
106 static void iotjs_i2c_destroy(iotjs_i2c_t* i2c) {
107   IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_i2c_t, i2c);
108   iotjs_jobjectwrap_destroy(&_this->jobjectwrap);
109   IOTJS_RELEASE(i2c);
110 }
111
112
113 iotjs_i2c_t* iotjs_i2c_instance_from_jval(const iotjs_jval_t* ji2c) {
114   iotjs_jobjectwrap_t* jobjectwrap = iotjs_jobjectwrap_from_jobject(ji2c);
115   return (iotjs_i2c_t*)jobjectwrap;
116 }
117
118
119 void AfterI2CWork(uv_work_t* work_req, int status) {
120   iotjs_i2c_reqwrap_t* req_wrap = iotjs_i2c_reqwrap_from_request(work_req);
121   iotjs_i2c_reqdata_t* req_data = iotjs_i2c_reqwrap_data(req_wrap);
122
123   iotjs_jargs_t jargs = iotjs_jargs_create(2);
124
125   if (status) {
126     iotjs_jval_t error = iotjs_jval_create_error("System error");
127     iotjs_jargs_append_jval(&jargs, &error);
128     iotjs_jval_destroy(&error);
129   } else {
130     switch (req_data->op) {
131       case kI2cOpOpen: {
132         if (req_data->error == kI2cErrOpen) {
133           iotjs_jval_t error =
134               iotjs_jval_create_error("Failed to open I2C device");
135           iotjs_jargs_append_jval(&jargs, &error);
136           iotjs_jval_destroy(&error);
137         } else {
138           iotjs_jargs_append_null(&jargs);
139         }
140         break;
141       }
142       case kI2cOpWrite:
143       case kI2cOpWriteByte:
144       case kI2cOpWriteBlock: {
145         if (req_data->error == kI2cErrWrite) {
146           iotjs_jval_t error =
147               iotjs_jval_create_error("Cannot write to device");
148           iotjs_jargs_append_jval(&jargs, &error);
149           iotjs_jval_destroy(&error);
150         } else {
151           iotjs_jargs_append_null(&jargs);
152         }
153         break;
154       }
155       case kI2cOpRead:
156       case kI2cOpReadBlock: {
157         if (req_data->error == kI2cErrRead) {
158           iotjs_jval_t error =
159               iotjs_jval_create_error("Cannot read from device");
160           iotjs_jargs_append_jval(&jargs, &error);
161           iotjs_jargs_append_null(&jargs);
162           iotjs_jval_destroy(&error);
163         } else if (req_data->error == kI2cErrReadBlock) {
164           iotjs_jval_t error =
165               iotjs_jval_create_error("Error reading length of bytes");
166           iotjs_jargs_append_jval(&jargs, &error);
167           iotjs_jargs_append_null(&jargs);
168           iotjs_jval_destroy(&error);
169         } else {
170           iotjs_jargs_append_null(&jargs);
171           iotjs_jval_t result =
172               iotjs_jval_create_byte_array(req_data->buf_len,
173                                            req_data->buf_data);
174           iotjs_jargs_append_jval(&jargs, &result);
175           iotjs_jval_destroy(&result);
176
177           if (req_data->delay > 0) {
178             uv_sleep(req_data->delay);
179           }
180
181           if (req_data->buf_data != NULL) {
182             iotjs_buffer_release(req_data->buf_data);
183           }
184         }
185         break;
186       }
187       case kI2cOpReadByte: {
188         if (req_data->error == kI2cErrRead) {
189           iotjs_jval_t error =
190               iotjs_jval_create_error("Cannot read from device");
191           iotjs_jargs_append_jval(&jargs, &error);
192           iotjs_jargs_append_null(&jargs);
193           iotjs_jval_destroy(&error);
194         } else {
195           iotjs_jargs_append_null(&jargs);
196           iotjs_jargs_append_number(&jargs, req_data->byte);
197         }
198         break;
199       }
200       default: {
201         IOTJS_ASSERT(!"Unreachable");
202         break;
203       }
204     }
205   }
206
207   const iotjs_jval_t* jcallback = iotjs_i2c_reqwrap_jcallback(req_wrap);
208   iotjs_make_callback(jcallback, iotjs_jval_get_undefined(), &jargs);
209
210   iotjs_jargs_destroy(&jargs);
211   iotjs_i2c_reqwrap_dispatched(req_wrap);
212 }
213
214
215 static void GetI2cArray(const iotjs_jval_t* jarray,
216                         iotjs_i2c_reqdata_t* req_data) {
217   // FIXME
218   // Need to implement a function to get array info from iotjs_jval_t Array.
219   iotjs_jval_t jlength =
220       iotjs_jval_get_property(jarray, IOTJS_MAGIC_STRING_LENGTH);
221   IOTJS_ASSERT(!iotjs_jval_is_undefined(&jlength));
222
223   req_data->buf_len = iotjs_jval_as_number(&jlength);
224   req_data->buf_data = iotjs_buffer_allocate(req_data->buf_len);
225
226   for (int i = 0; i < req_data->buf_len; i++) {
227     iotjs_jval_t jdata = iotjs_jval_get_property_by_index(jarray, i);
228     req_data->buf_data[i] = iotjs_jval_as_number(&jdata);
229     iotjs_jval_destroy(&jdata);
230   }
231
232   iotjs_jval_destroy(&jlength);
233 }
234
235
236 #define I2C_ASYNC(op)                                                  \
237   do {                                                                 \
238     uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); \
239     uv_work_t* req = iotjs_i2c_reqwrap_req(req_wrap);                  \
240     uv_queue_work(loop, req, op##Worker, AfterI2CWork);                \
241   } while (0)
242
243
244 JHANDLER_FUNCTION(I2cCons) {
245   JHANDLER_CHECK_THIS(object);
246 #if defined(__linux__) || defined(__APPLE__)
247   JHANDLER_CHECK_ARGS(2, string, function);
248   iotjs_string_t device = JHANDLER_GET_ARG(0, string);
249 #elif defined(__NUTTX__)
250   JHANDLER_CHECK_ARGS(2, number, function);
251   uint32_t device = JHANDLER_GET_ARG(0, number);
252 #endif
253
254   // Create I2C object
255   const iotjs_jval_t* ji2c = JHANDLER_GET_THIS(object);
256   iotjs_i2c_t* i2c = iotjs_i2c_create(ji2c);
257   IOTJS_ASSERT(i2c ==
258                (iotjs_i2c_t*)(iotjs_jval_get_object_native_handle(ji2c)));
259
260   // Create I2C request wrap
261   const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(1, function);
262   iotjs_i2c_reqwrap_t* req_wrap =
263       iotjs_i2c_reqwrap_create(jcallback, ji2c, kI2cOpOpen);
264
265   iotjs_i2c_reqdata_t* req_data = iotjs_i2c_reqwrap_data(req_wrap);
266 #if defined(__linux__) || defined(__APPLE__)
267   iotjs_string_append(&req_data->device, iotjs_string_data(&device),
268                       iotjs_string_size(&device));
269 #elif defined(__NUTTX__)
270   req_data->device = device;
271 #endif
272
273   I2C_ASYNC(Open);
274 }
275
276
277 JHANDLER_FUNCTION(SetAddress) {
278   JHANDLER_CHECK_THIS(object);
279   JHANDLER_CHECK_ARGS(1, number);
280   iotjs_i2c_t* i2c = iotjs_i2c_instance_from_jval(JHANDLER_GET_THIS(object));
281
282   I2cSetAddress(i2c, JHANDLER_GET_ARG(0, number));
283
284   iotjs_jhandler_return_null(jhandler);
285 }
286
287
288 JHANDLER_FUNCTION(Close) {
289   JHANDLER_CHECK_THIS(object);
290   JHANDLER_CHECK_ARGS(0);
291
292   iotjs_i2c_t* i2c = iotjs_i2c_instance_from_jval(JHANDLER_GET_THIS(object));
293   I2cClose(i2c);
294
295   iotjs_jhandler_return_null(jhandler);
296 }
297
298
299 JHANDLER_FUNCTION(Write) {
300   JHANDLER_CHECK_THIS(object);
301   JHANDLER_CHECK_ARGS(2, array, function);
302
303   const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(1, function);
304   const iotjs_jval_t* ji2c = JHANDLER_GET_THIS(object);
305
306   iotjs_i2c_reqwrap_t* req_wrap =
307       iotjs_i2c_reqwrap_create(jcallback, ji2c, kI2cOpWrite);
308   iotjs_i2c_reqdata_t* req_data = iotjs_i2c_reqwrap_data(req_wrap);
309
310   GetI2cArray(JHANDLER_GET_ARG(0, array), req_data);
311
312   I2C_ASYNC(Write);
313
314   iotjs_jhandler_return_null(jhandler);
315 }
316
317
318 JHANDLER_FUNCTION(WriteByte) {
319   JHANDLER_CHECK_THIS(object);
320   JHANDLER_CHECK_ARGS(2, number, function);
321
322   uint8_t byte = JHANDLER_GET_ARG(0, number);
323   const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(1, function);
324   const iotjs_jval_t* ji2c = JHANDLER_GET_THIS(object);
325
326   iotjs_i2c_reqwrap_t* req_wrap =
327       iotjs_i2c_reqwrap_create(jcallback, ji2c, kI2cOpWriteByte);
328
329   iotjs_i2c_reqdata_t* req_data = iotjs_i2c_reqwrap_data(req_wrap);
330   req_data->byte = byte;
331
332   I2C_ASYNC(WriteByte);
333
334   iotjs_jhandler_return_null(jhandler);
335 }
336
337
338 JHANDLER_FUNCTION(WriteBlock) {
339   JHANDLER_CHECK_THIS(object);
340   JHANDLER_CHECK_ARGS(3, number, array, function);
341
342   const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(2, function);
343   const iotjs_jval_t* ji2c = JHANDLER_GET_THIS(object);
344
345   iotjs_i2c_reqwrap_t* req_wrap =
346       iotjs_i2c_reqwrap_create(jcallback, ji2c, kI2cOpWriteBlock);
347
348   iotjs_i2c_reqdata_t* req_data = iotjs_i2c_reqwrap_data(req_wrap);
349   req_data->cmd = JHANDLER_GET_ARG(0, number);
350   GetI2cArray(JHANDLER_GET_ARG(1, array), req_data);
351
352   I2C_ASYNC(WriteBlock);
353
354   iotjs_jhandler_return_null(jhandler);
355 }
356
357
358 JHANDLER_FUNCTION(Read) {
359   JHANDLER_CHECK_THIS(object);
360   JHANDLER_CHECK_ARGS(2, number, function);
361
362   const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(1, function);
363   const iotjs_jval_t* ji2c = JHANDLER_GET_THIS(object);
364
365   iotjs_i2c_reqwrap_t* req_wrap =
366       iotjs_i2c_reqwrap_create(jcallback, ji2c, kI2cOpRead);
367
368   iotjs_i2c_reqdata_t* req_data = iotjs_i2c_reqwrap_data(req_wrap);
369   req_data->buf_len = JHANDLER_GET_ARG(0, number);
370   req_data->delay = 0;
371
372   I2C_ASYNC(Read);
373
374   iotjs_jhandler_return_null(jhandler);
375 }
376
377
378 JHANDLER_FUNCTION(ReadByte) {
379   JHANDLER_CHECK_THIS(object);
380   JHANDLER_CHECK_ARGS(1, function);
381
382   const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(0, function);
383   const iotjs_jval_t* ji2c = JHANDLER_GET_THIS(object);
384
385   iotjs_i2c_reqwrap_t* req_wrap =
386       iotjs_i2c_reqwrap_create(jcallback, ji2c, kI2cOpReadByte);
387
388   I2C_ASYNC(ReadByte);
389
390   iotjs_jhandler_return_null(jhandler);
391 }
392
393
394 JHANDLER_FUNCTION(ReadBlock) {
395   JHANDLER_CHECK_THIS(object);
396   JHANDLER_CHECK_ARGS(4, number, number, number, function);
397
398   const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(3, function);
399   const iotjs_jval_t* ji2c = JHANDLER_GET_THIS(object);
400
401   iotjs_i2c_reqwrap_t* req_wrap =
402       iotjs_i2c_reqwrap_create(jcallback, ji2c, kI2cOpReadBlock);
403
404   iotjs_i2c_reqdata_t* req_data = iotjs_i2c_reqwrap_data(req_wrap);
405   req_data->cmd = JHANDLER_GET_ARG(0, number);
406   req_data->buf_len = JHANDLER_GET_ARG(1, number);
407   req_data->delay = JHANDLER_GET_ARG(2, number);
408
409   I2C_ASYNC(ReadBlock);
410
411   iotjs_jhandler_return_null(jhandler);
412 }
413
414
415 iotjs_jval_t InitI2c() {
416   iotjs_jval_t jI2cCons = iotjs_jval_create_function_with_dispatch(I2cCons);
417
418   iotjs_jval_t prototype = iotjs_jval_create_object();
419
420   iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_SETADDRESS, SetAddress);
421   iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_CLOSE, Close);
422   iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_WRITE, Write);
423   iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_WRITEBYTE, WriteByte);
424   iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_WRITEBLOCK, WriteBlock);
425   iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_READ, Read);
426   iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_READBYTE, ReadByte);
427   iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_READBLOCK, ReadBlock);
428
429   iotjs_jval_set_property_jval(&jI2cCons, IOTJS_MAGIC_STRING_PROTOTYPE,
430                                &prototype);
431
432   iotjs_jval_destroy(&prototype);
433
434   return jI2cCons;
435 }