Update Iot.js
[platform/upstream/iotjs.git] / src / platform / iotjs_module_i2c-linux-general.inl.h
1 /* The MIT License (MIT)
2  *
3  * Copyright (c) 2005-2014 RoadNarrows LLC.
4  * http://roadnarrows.com
5  * All Rights Reserved
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom
12  * the Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  */
25
26 /* Copyright 2016-present Samsung Electronics Co., Ltd. and other contributors
27  *
28  * Licensed under the Apache License, Version 2.0 (the "License");
29  * you may not use this file except in compliance with the License.
30  * You may obtain a copy of the License at
31  *
32  *     http://www.apache.org/licenses/LICENSE-2.0
33  *
34  * Unless required by applicable law or agreed to in writing, software
35  * distributed under the License is distributed on an "AS IS" BASIS
36  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
37  * See the License for the specific language governing permissions and
38  * limitations under the License.
39  */
40
41
42 /* Some functions are modified from the RoadNarrows-robotics i2c library.
43  * (distributed under the MIT license.)
44  */
45
46
47 #ifndef IOTJS_MODULE_I2C_LINUX_GENERAL_INL_H
48 #define IOTJS_MODULE_I2C_LINUX_GENERAL_INL_H
49
50
51 #include <fcntl.h>
52 #include <stdint.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <sys/ioctl.h>
57 #include <sys/stat.h>
58 #include <sys/types.h>
59 #include <unistd.h>
60
61
62 #include "module/iotjs_module_i2c.h"
63
64
65 #define I2C_SLAVE_FORCE 0x0706
66 #define I2C_SMBUS 0x0720
67 #define I2C_SMBUS_READ 1
68 #define I2C_SMBUS_WRITE 0
69 #define I2C_NOCMD 0
70 #define I2C_SMBUS_BYTE 1
71 #define I2C_SMBUS_BLOCK_DATA 5
72 #define I2C_SMBUS_I2C_BLOCK_DATA 8
73 #define I2C_SMBUS_BLOCK_MAX 32
74 #define I2C_MAX_ADDRESS 128
75
76
77 typedef union I2cSmbusDataUnion {
78   uint8_t byte;
79   unsigned short word;
80   uint8_t block[I2C_SMBUS_BLOCK_MAX + 2];
81 } I2cSmbusData;
82
83
84 typedef struct I2cSmbusIoctlDataStruct {
85   uint8_t read_write;
86   uint8_t command;
87   int size;
88   I2cSmbusData* data;
89 } I2cSmbusIoctlData;
90
91
92 static int current_fd;
93 static uint8_t addr;
94
95
96 int I2cSmbusAccess(int fd, uint8_t read_write, uint8_t command, int size,
97                    I2cSmbusData* data) {
98   I2cSmbusIoctlData args;
99
100   args.read_write = read_write;
101   args.command = command;
102   args.size = size;
103   args.data = data;
104
105   return ioctl(fd, I2C_SMBUS, &args);
106 }
107
108
109 int I2cSmbusWriteByte(int fd, uint8_t byte) {
110   return I2cSmbusAccess(fd, I2C_SMBUS_WRITE, byte, I2C_SMBUS_BYTE, NULL);
111 }
112
113
114 int I2cSmbusWriteI2cBlockData(int fd, uint8_t command, uint8_t* values,
115                               uint8_t length) {
116   I2cSmbusData data;
117
118   if (length > I2C_SMBUS_BLOCK_MAX) {
119     length = I2C_SMBUS_BLOCK_MAX;
120   }
121
122   for (int i = 1; i <= length; i++) {
123     data.block[i] = values[i - 1];
124   }
125   data.block[0] = length;
126
127   return I2cSmbusAccess(fd, I2C_SMBUS_WRITE, command, I2C_SMBUS_I2C_BLOCK_DATA,
128                         &data);
129 }
130
131
132 int I2cSmbusReadByte(int fd) {
133   I2cSmbusData data;
134
135   int result =
136       I2cSmbusAccess(fd, I2C_SMBUS_READ, I2C_NOCMD, I2C_SMBUS_BYTE, &data);
137
138   // Mask one byte from result (data.byte).
139   return result >= 0 ? 0xFF & data.byte : -1;
140 }
141
142
143 int I2cSmbusReadI2cBlockData(int fd, uint8_t command, uint8_t* values,
144                              uint8_t length) {
145   I2cSmbusData data;
146
147   if (length > I2C_SMBUS_BLOCK_MAX) {
148     length = I2C_SMBUS_BLOCK_MAX;
149   }
150   data.block[0] = length;
151
152   int result = I2cSmbusAccess(fd, I2C_SMBUS_READ, command,
153                               I2C_SMBUS_I2C_BLOCK_DATA, &data);
154   if (result >= 0) {
155     for (int i = 1; i <= data.block[0]; i++) {
156       values[i - 1] = data.block[i];
157     }
158     result = data.block[0];
159   }
160
161   return result;
162 }
163
164
165 #define I2C_WORKER_INIT_TEMPLATE                                            \
166   iotjs_i2c_reqwrap_t* req_wrap = iotjs_i2c_reqwrap_from_request(work_req); \
167   iotjs_i2c_reqdata_t* req_data = iotjs_i2c_reqwrap_data(req_wrap);
168
169
170 void I2cSetAddress(iotjs_i2c_t* i2c, uint8_t address) {
171   addr = address;
172   ioctl(current_fd, I2C_SLAVE_FORCE, addr);
173 }
174
175
176 void OpenWorker(uv_work_t* work_req) {
177   I2C_WORKER_INIT_TEMPLATE;
178
179   current_fd = open(iotjs_string_data(&req_data->device), O_RDWR);
180
181   if (current_fd == -1) {
182     req_data->error = kI2cErrOpen;
183   } else {
184     req_data->error = kI2cErrOk;
185   }
186 }
187
188
189 void I2cClose(iotjs_i2c_t* i2c) {
190   if (current_fd > 0) {
191     close(current_fd);
192   }
193 }
194
195
196 void WriteWorker(uv_work_t* work_req) {
197   I2C_WORKER_INIT_TEMPLATE;
198
199   uint8_t len = req_data->buf_len;
200   char* data = req_data->buf_data;
201
202   if (write(current_fd, data, len) != len) {
203     req_data->error = kI2cErrWrite;
204   }
205
206   if (req_data->buf_data != NULL) {
207     iotjs_buffer_release(req_data->buf_data);
208   }
209 }
210
211
212 void WriteByteWorker(uv_work_t* work_req) {
213   I2C_WORKER_INIT_TEMPLATE;
214
215   if (I2cSmbusWriteByte(current_fd, req_data->byte) == -1) {
216     req_data->error = kI2cErrWrite;
217   }
218 }
219
220
221 void WriteBlockWorker(uv_work_t* work_req) {
222   I2C_WORKER_INIT_TEMPLATE;
223
224   uint8_t cmd = req_data->cmd;
225   uint8_t len = req_data->buf_len;
226   uint8_t* data = (uint8_t*)(req_data->buf_data);
227
228   if (I2cSmbusWriteI2cBlockData(current_fd, cmd, data, len) == -1) {
229     req_data->error = kI2cErrWrite;
230   }
231
232   if (req_data->buf_data != NULL) {
233     iotjs_buffer_release(req_data->buf_data);
234   }
235 }
236
237
238 void ReadWorker(uv_work_t* work_req) {
239   I2C_WORKER_INIT_TEMPLATE;
240
241   uint8_t len = req_data->buf_len;
242   req_data->buf_data = iotjs_buffer_allocate(len);
243
244   if (read(current_fd, req_data->buf_data, len) != len) {
245     req_data->error = kI2cErrRead;
246   }
247 }
248
249
250 void ReadByteWorker(uv_work_t* work_req) {
251   I2C_WORKER_INIT_TEMPLATE;
252
253   int result = I2cSmbusReadByte(current_fd);
254   if (result == -1) {
255     req_data->error = kI2cErrRead;
256   } else {
257     req_data->byte = result;
258   }
259 }
260
261
262 void ReadBlockWorker(uv_work_t* work_req) {
263   I2C_WORKER_INIT_TEMPLATE;
264
265   uint8_t cmd = req_data->cmd;
266   uint8_t len = req_data->buf_len;
267   uint8_t data[I2C_SMBUS_BLOCK_MAX + 2];
268
269   if (I2cSmbusReadI2cBlockData(current_fd, cmd, data, len) != len) {
270     req_data->error = kI2cErrReadBlock;
271   }
272
273   req_data->buf_data = iotjs_buffer_allocate(len);
274   memcpy(req_data->buf_data, data, len);
275 }
276
277
278 #endif /* IOTJS_MODULE_I2C_LINUX_GENERAL_INL_H */