i2c 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/i2c.cc CHANGED
@@ -1,6 +1,4 @@
1
- #include <node.h>
2
- #include <node_buffer.h>
3
- #include <nan.h>
1
+ #include <node_api.h>
4
2
  #include <fcntl.h>
5
3
  #include <stdint.h>
6
4
  #include <errno.h>
@@ -8,300 +6,911 @@
8
6
  #include <stdio.h>
9
7
  #include <unistd.h>
10
8
  #include <string.h>
11
- #include <vector>
9
+ #include <stdlib.h>
12
10
  #include "i2c-dev.h"
13
11
 
12
+ #define MAX_READ_LEN 1024
13
+ #define I2C_ADDR_COUNT 128
14
14
 
15
- using namespace v8;
16
- int fd;
17
- int8_t addr;
15
+ typedef struct {
16
+ int fd;
17
+ int8_t addr;
18
+ bool is_open;
19
+ } I2CDevice;
18
20
 
19
- void setAddress(int8_t addr) {
20
- Isolate* isolate = Isolate::GetCurrent();
21
- Nan::HandleScope scope;
21
+ static void device_destructor(napi_env env, void* data, void* hint) {
22
+ I2CDevice* device = (I2CDevice*)data;
23
+ if (device->is_open) {
24
+ close(device->fd);
25
+ }
26
+ free(device);
27
+ }
28
+
29
+ // --- Helper: unwrap device from `this` ---
30
+
31
+ static I2CDevice* unwrap_device(napi_env env, napi_callback_info info) {
32
+ napi_value jsthis;
33
+ napi_get_cb_info(env, info, NULL, NULL, &jsthis, NULL);
34
+ I2CDevice* device;
35
+ napi_unwrap(env, jsthis, (void**)&device);
36
+ return device;
37
+ }
38
+
39
+ // --- Helper: check device is open, throw if not ---
40
+
41
+ static bool require_open(napi_env env, I2CDevice* device) {
42
+ if (!device->is_open) {
43
+ napi_throw_error(env, NULL, "Device is not open");
44
+ return false;
45
+ }
46
+ return true;
47
+ }
48
+
49
+ // --- Constructor ---
50
+
51
+ static napi_value New(napi_env env, napi_callback_info info) {
52
+ napi_value jsthis;
53
+ napi_get_cb_info(env, info, NULL, NULL, &jsthis, NULL);
54
+
55
+ I2CDevice* device = (I2CDevice*)malloc(sizeof(I2CDevice));
56
+ if (!device) {
57
+ napi_throw_error(env, NULL, "Failed to allocate I2CDevice");
58
+ return NULL;
59
+ }
60
+ device->fd = -1;
61
+ device->addr = 0;
62
+ device->is_open = false;
63
+
64
+ napi_wrap(env, jsthis, device, device_destructor, NULL, NULL);
65
+ return jsthis;
66
+ }
67
+
68
+ // --- Synchronous: SetAddress ---
69
+
70
+ static napi_value SetAddress(napi_env env, napi_callback_info info) {
71
+ size_t argc = 1;
72
+ napi_value argv[1], jsthis;
73
+ napi_get_cb_info(env, info, &argc, argv, &jsthis, NULL);
22
74
 
23
- int result = ioctl(fd, I2C_SLAVE_FORCE, addr);
75
+ I2CDevice* device;
76
+ napi_unwrap(env, jsthis, (void**)&device);
77
+
78
+ if (!require_open(env, device)) return NULL;
79
+
80
+ int32_t addr;
81
+ napi_get_value_int32(env, argv[0], &addr);
82
+
83
+ device->addr = (int8_t)addr;
84
+ int result = ioctl(device->fd, I2C_SLAVE_FORCE, device->addr);
24
85
  if (result == -1) {
25
- isolate->ThrowException(
26
- Exception::TypeError(Nan::New("Failed to set address").ToLocalChecked())
27
- );
28
- return;
86
+ char msg[256];
87
+ snprintf(msg, sizeof(msg), "Failed to set address 0x%02x: %s", addr, strerror(errno));
88
+ napi_throw_error(env, NULL, msg);
89
+ }
90
+
91
+ return NULL;
92
+ }
93
+
94
+ // --- Synchronous: Close ---
95
+
96
+ static napi_value Close(napi_env env, napi_callback_info info) {
97
+ I2CDevice* device = unwrap_device(env, info);
98
+ if (device->is_open) {
99
+ close(device->fd);
100
+ device->fd = -1;
101
+ device->is_open = false;
29
102
  }
103
+ return NULL;
30
104
  }
31
105
 
32
- void SetAddress(const Nan::FunctionCallbackInfo<v8::Value>& info) {
33
- Nan::HandleScope scope;
106
+ // ============================================================
107
+ // Async worker infrastructure
108
+ //
109
+ // Every async operation holds a napi_ref to the JS `this` object
110
+ // to prevent garbage collection of the I2CDevice while the
111
+ // worker thread is accessing it.
112
+ //
113
+ // Before queuing work, we snapshot the fd from the device so
114
+ // the worker thread uses a stable copy. If the device is closed
115
+ // concurrently, the worst case is an EBADF error (not a use of
116
+ // a recycled fd), because close() sets device->fd = -1 and the
117
+ // kernel won't reuse an fd until close() returns.
118
+ // ============================================================
119
+
120
+ // --- Open ---
121
+
122
+ typedef struct {
123
+ I2CDevice* device;
124
+ napi_async_work work;
125
+ napi_ref callback_ref;
126
+ napi_ref this_ref;
127
+ char device_path[256];
128
+ int result_fd;
129
+ int err_no;
130
+ } OpenWorkData;
131
+
132
+ static void open_execute(napi_env env, void* data) {
133
+ OpenWorkData* d = (OpenWorkData*)data;
134
+ d->result_fd = open(d->device_path, O_RDWR);
135
+ if (d->result_fd == -1) {
136
+ d->err_no = errno;
137
+ }
138
+ }
139
+
140
+ static void open_complete(napi_env env, napi_status status, void* data) {
141
+ OpenWorkData* d = (OpenWorkData*)data;
142
+
143
+ napi_value callback, global, argv[1];
144
+ napi_get_reference_value(env, d->callback_ref, &callback);
145
+ napi_get_global(env, &global);
34
146
 
35
- if (!info[0]->IsNumber()) {
36
- Nan::ThrowTypeError("addr must be an int");
37
- return;
147
+ if (d->result_fd == -1) {
148
+ char msg[512];
149
+ snprintf(msg, sizeof(msg), "Failed to open I2C device %s: %s", d->device_path, strerror(d->err_no));
150
+ napi_value err_msg;
151
+ napi_create_string_utf8(env, msg, NAPI_AUTO_LENGTH, &err_msg);
152
+ napi_create_error(env, NULL, err_msg, &argv[0]);
153
+ } else {
154
+ d->device->fd = d->result_fd;
155
+ d->device->is_open = true;
156
+ napi_get_null(env, &argv[0]);
38
157
  }
39
- addr = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust();
40
- setAddress(addr);
158
+
159
+ napi_call_function(env, global, callback, 1, argv, NULL);
160
+ napi_delete_reference(env, d->callback_ref);
161
+ napi_delete_reference(env, d->this_ref);
162
+ napi_delete_async_work(env, d->work);
163
+ free(d);
41
164
  }
42
165
 
43
- void Scan(const Nan::FunctionCallbackInfo<v8::Value>& info) {
44
- Nan::HandleScope scope;
166
+ static napi_value Open(napi_env env, napi_callback_info info) {
167
+ size_t argc = 2;
168
+ napi_value argv[2], jsthis;
169
+ napi_get_cb_info(env, info, &argc, argv, &jsthis, NULL);
45
170
 
46
- int i, res;
47
- Local<Function> callback = Local<Function>::Cast(info[0]);
48
- Local<Array> results = Nan::New<Array>(128);
49
- Local<Value> err = Nan::New<Value>(Nan::Null());
171
+ I2CDevice* device;
172
+ napi_unwrap(env, jsthis, (void**)&device);
173
+
174
+ OpenWorkData* d = (OpenWorkData*)malloc(sizeof(OpenWorkData));
175
+ if (!d) {
176
+ napi_throw_error(env, NULL, "Failed to allocate memory for open operation");
177
+ return NULL;
178
+ }
179
+ d->device = device;
180
+ d->err_no = 0;
50
181
 
51
- for (i = 0; i < 128; i++) {
52
- setAddress(i);
182
+ size_t path_len;
183
+ napi_get_value_string_utf8(env, argv[0], d->device_path, sizeof(d->device_path), &path_len);
184
+
185
+ napi_create_reference(env, argv[1], 1, &d->callback_ref);
186
+ napi_create_reference(env, jsthis, 1, &d->this_ref);
187
+
188
+ napi_value resource_name;
189
+ napi_create_string_utf8(env, "i2c:open", NAPI_AUTO_LENGTH, &resource_name);
190
+ napi_create_async_work(env, NULL, resource_name, open_execute, open_complete, d, &d->work);
191
+ napi_queue_async_work(env, d->work);
192
+
193
+ return NULL;
194
+ }
195
+
196
+ // --- Scan ---
197
+
198
+ typedef struct {
199
+ I2CDevice* device;
200
+ napi_async_work work;
201
+ napi_ref callback_ref;
202
+ napi_ref this_ref;
203
+ int fd; // snapshot of device->fd at queue time
204
+ int8_t original_addr;
205
+ int results[I2C_ADDR_COUNT];
206
+ } ScanWorkData;
207
+
208
+ static void scan_execute(napi_env env, void* data) {
209
+ ScanWorkData* d = (ScanWorkData*)data;
210
+ int fd = d->fd;
211
+
212
+ for (int i = 0; i < I2C_ADDR_COUNT; i++) {
213
+ if (ioctl(fd, I2C_SLAVE_FORCE, i) < 0) {
214
+ d->results[i] = -1;
215
+ continue;
216
+ }
217
+
218
+ int res;
53
219
  if ((i >= 0x30 && i <= 0x37) || (i >= 0x50 && i <= 0x5F)) {
54
220
  res = i2c_smbus_read_byte(fd);
55
- } else {
221
+ } else {
56
222
  res = i2c_smbus_write_quick(fd, I2C_SMBUS_WRITE);
57
223
  }
58
- if (res >= 0) {
59
- res = i;
60
- }
61
- Nan::Set(results, i, Nan::New<Integer>(res));
224
+ d->results[i] = (res >= 0) ? i : -1;
62
225
  }
63
226
 
64
- setAddress(addr);
227
+ // Restore original address
228
+ ioctl(fd, I2C_SLAVE_FORCE, d->original_addr);
229
+ }
230
+
231
+ static void scan_complete(napi_env env, napi_status status, void* data) {
232
+ ScanWorkData* d = (ScanWorkData*)data;
233
+
234
+ napi_value callback, global, argv[2];
235
+ napi_get_reference_value(env, d->callback_ref, &callback);
236
+ napi_get_global(env, &global);
65
237
 
66
- const unsigned argc = 2;
67
- Local<Value> argv[argc] = { err, results };
238
+ napi_get_null(env, &argv[0]);
68
239
 
69
- Nan::Call(callback, Nan::GetCurrentContext()->Global(), argc, argv);
240
+ napi_value results;
241
+ napi_create_array_with_length(env, I2C_ADDR_COUNT, &results);
242
+ for (int i = 0; i < I2C_ADDR_COUNT; i++) {
243
+ napi_value val;
244
+ napi_create_int32(env, d->results[i], &val);
245
+ napi_set_element(env, results, i, val);
246
+ }
247
+ argv[1] = results;
70
248
 
71
- info.GetReturnValue().Set(results);
249
+ napi_call_function(env, global, callback, 2, argv, NULL);
250
+ napi_delete_reference(env, d->callback_ref);
251
+ napi_delete_reference(env, d->this_ref);
252
+ napi_delete_async_work(env, d->work);
253
+ free(d);
72
254
  }
73
255
 
74
- void Close(const Nan::FunctionCallbackInfo<v8::Value>& info) {
75
- Nan::HandleScope scope;
256
+ static napi_value Scan(napi_env env, napi_callback_info info) {
257
+ size_t argc = 1;
258
+ napi_value argv[1], jsthis;
259
+ napi_get_cb_info(env, info, &argc, argv, &jsthis, NULL);
260
+
261
+ I2CDevice* device;
262
+ napi_unwrap(env, jsthis, (void**)&device);
76
263
 
77
- if (fd > 0) {
78
- close(fd);
264
+ if (!require_open(env, device)) return NULL;
265
+
266
+ ScanWorkData* d = (ScanWorkData*)malloc(sizeof(ScanWorkData));
267
+ if (!d) {
268
+ napi_throw_error(env, NULL, "Failed to allocate memory for scan operation");
269
+ return NULL;
79
270
  }
80
- }
271
+ d->device = device;
272
+ d->fd = device->fd;
273
+ d->original_addr = device->addr;
81
274
 
82
- void Open(const Nan::FunctionCallbackInfo<v8::Value>& info) {
83
- Nan::HandleScope scope;
275
+ napi_create_reference(env, argv[0], 1, &d->callback_ref);
276
+ napi_create_reference(env, jsthis, 1, &d->this_ref);
84
277
 
85
- Nan::Utf8String device(info[0]);
86
- Local<Value> err = Nan::New<Value>(Nan::Null());
278
+ napi_value resource_name;
279
+ napi_create_string_utf8(env, "i2c:scan", NAPI_AUTO_LENGTH, &resource_name);
280
+ napi_create_async_work(env, NULL, resource_name, scan_execute, scan_complete, d, &d->work);
281
+ napi_queue_async_work(env, d->work);
87
282
 
88
- fd = open(*device, O_RDWR);
89
- if (fd == -1) {
90
- err = Nan::Error(Nan::New("Failed to open I2C device").ToLocalChecked());
283
+ return NULL;
284
+ }
285
+
286
+ // --- Read ---
287
+
288
+ typedef struct {
289
+ napi_async_work work;
290
+ napi_ref callback_ref;
291
+ napi_ref this_ref;
292
+ int fd;
293
+ int len;
294
+ uint8_t* buf;
295
+ int bytes_read;
296
+ int err_no;
297
+ } ReadWorkData;
298
+
299
+ static void read_execute(napi_env env, void* data) {
300
+ ReadWorkData* d = (ReadWorkData*)data;
301
+ d->bytes_read = read(d->fd, d->buf, d->len);
302
+ if (d->bytes_read < 0) {
303
+ d->err_no = errno;
91
304
  }
305
+ }
306
+
307
+ static void read_complete(napi_env env, napi_status status, void* data) {
308
+ ReadWorkData* d = (ReadWorkData*)data;
92
309
 
93
- if (info[1]->IsFunction()) {
94
- const unsigned argc = 1;
95
- Local<Function> callback = Local<Function>::Cast(info[1]);
96
- Local<Value> argv[argc] = { err };
97
- Nan::Call(callback, Nan::GetCurrentContext()->Global(), argc, argv);
310
+ napi_value callback, global, argv[2];
311
+ napi_get_reference_value(env, d->callback_ref, &callback);
312
+ napi_get_global(env, &global);
313
+
314
+ if (d->bytes_read < 0) {
315
+ char msg[256];
316
+ snprintf(msg, sizeof(msg), "Cannot read from device: %s", strerror(d->err_no));
317
+ napi_value err_msg;
318
+ napi_create_string_utf8(env, msg, NAPI_AUTO_LENGTH, &err_msg);
319
+ napi_create_error(env, NULL, err_msg, &argv[0]);
320
+ napi_get_undefined(env, &argv[1]);
321
+ } else {
322
+ napi_get_null(env, &argv[0]);
323
+ napi_value arr;
324
+ napi_create_array_with_length(env, d->bytes_read, &arr);
325
+ for (int i = 0; i < d->bytes_read; i++) {
326
+ napi_value val;
327
+ napi_create_int32(env, d->buf[i], &val);
328
+ napi_set_element(env, arr, i, val);
329
+ }
330
+ argv[1] = arr;
98
331
  }
332
+
333
+ napi_call_function(env, global, callback, 2, argv, NULL);
334
+ napi_delete_reference(env, d->callback_ref);
335
+ napi_delete_reference(env, d->this_ref);
336
+ napi_delete_async_work(env, d->work);
337
+ free(d->buf);
338
+ free(d);
99
339
  }
100
340
 
101
- void Read(const Nan::FunctionCallbackInfo<v8::Value>& info) {
102
- Nan::HandleScope scope;
341
+ static napi_value Read(napi_env env, napi_callback_info info) {
342
+ size_t argc = 2;
343
+ napi_value argv[2], jsthis;
344
+ napi_get_cb_info(env, info, &argc, argv, &jsthis, NULL);
103
345
 
104
- int len = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust();
346
+ I2CDevice* device;
347
+ napi_unwrap(env, jsthis, (void**)&device);
105
348
 
106
- Local<Array> data = Nan::New<Array>();
349
+ if (!require_open(env, device)) return NULL;
107
350
 
108
- char* buf = new char[len];
109
- Local<Value> err = Nan::New<Value>(Nan::Null());
351
+ int32_t len;
352
+ napi_get_value_int32(env, argv[0], &len);
110
353
 
111
- if (read(fd, buf, len) != len) {
112
- err = Nan::Error(Nan::New("Cannot read from device").ToLocalChecked());
113
- } else {
114
- for (int i = 0; i < len; ++i) {
115
- Nan::Set(data, i, Nan::New<Integer>(buf[i]));
116
- }
354
+ if (len <= 0 || len > MAX_READ_LEN) {
355
+ napi_throw_range_error(env, NULL, "read length must be between 1 and 1024");
356
+ return NULL;
117
357
  }
118
- delete[] buf;
119
358
 
120
- if (info[1]->IsFunction()) {
121
- const unsigned argc = 2;
122
- Local<Function> callback = Local<Function>::Cast(info[1]);
123
- Local<Value> argv[argc] = { err, data };
124
- Nan::Call(callback, Nan::GetCurrentContext()->Global(), argc, argv);
359
+ ReadWorkData* d = (ReadWorkData*)malloc(sizeof(ReadWorkData));
360
+ if (!d) {
361
+ napi_throw_error(env, NULL, "Failed to allocate memory for read operation");
362
+ return NULL;
125
363
  }
364
+ d->fd = device->fd;
365
+ d->len = len;
366
+ d->buf = (uint8_t*)malloc(len);
367
+ if (!d->buf) {
368
+ free(d);
369
+ napi_throw_error(env, NULL, "Failed to allocate read buffer");
370
+ return NULL;
371
+ }
372
+ d->bytes_read = 0;
373
+ d->err_no = 0;
374
+
375
+ napi_create_reference(env, argv[1], 1, &d->callback_ref);
376
+ napi_create_reference(env, jsthis, 1, &d->this_ref);
377
+
378
+ napi_value resource_name;
379
+ napi_create_string_utf8(env, "i2c:read", NAPI_AUTO_LENGTH, &resource_name);
380
+ napi_create_async_work(env, NULL, resource_name, read_execute, read_complete, d, &d->work);
381
+ napi_queue_async_work(env, d->work);
382
+
383
+ return NULL;
126
384
  }
127
385
 
128
- void ReadByte(const Nan::FunctionCallbackInfo<v8::Value>& info) {
129
- Nan::HandleScope scope;
130
-
131
- Local<Value> data;
132
- Local<Value> err = Nan::New<Value>(Nan::Null());
386
+ // --- ReadByte ---
387
+
388
+ typedef struct {
389
+ napi_async_work work;
390
+ napi_ref callback_ref;
391
+ napi_ref this_ref;
392
+ int fd;
393
+ int32_t result;
394
+ int err_no;
395
+ } ReadByteWorkData;
396
+
397
+ static void read_byte_execute(napi_env env, void* data) {
398
+ ReadByteWorkData* d = (ReadByteWorkData*)data;
399
+ d->result = i2c_smbus_read_byte(d->fd);
400
+ if (d->result == -1) {
401
+ d->err_no = errno;
402
+ }
403
+ }
133
404
 
134
- int32_t res = i2c_smbus_read_byte(fd);
405
+ static void read_byte_complete(napi_env env, napi_status status, void* data) {
406
+ ReadByteWorkData* d = (ReadByteWorkData*)data;
135
407
 
136
- if (res == -1) {
137
- err = Nan::Error(Nan::New("Cannot read device").ToLocalChecked());
408
+ napi_value callback, global, argv[2];
409
+ napi_get_reference_value(env, d->callback_ref, &callback);
410
+ napi_get_global(env, &global);
411
+
412
+ if (d->result == -1) {
413
+ char msg[256];
414
+ snprintf(msg, sizeof(msg), "Cannot read byte from device: %s", strerror(d->err_no));
415
+ napi_value err_msg;
416
+ napi_create_string_utf8(env, msg, NAPI_AUTO_LENGTH, &err_msg);
417
+ napi_create_error(env, NULL, err_msg, &argv[0]);
418
+ napi_get_undefined(env, &argv[1]);
138
419
  } else {
139
- data = Nan::New<Integer>(res);
420
+ napi_get_null(env, &argv[0]);
421
+ napi_create_int32(env, d->result, &argv[1]);
140
422
  }
141
423
 
142
- if (info[0]->IsFunction()) {
143
- const unsigned argc = 2;
144
- Local<Function> callback = Local<Function>::Cast(info[0]);
145
- Local<Value> argv[argc] = { err, data };
146
- Nan::Call(callback, Nan::GetCurrentContext()->Global(), argc, argv);
424
+ napi_call_function(env, global, callback, 2, argv, NULL);
425
+ napi_delete_reference(env, d->callback_ref);
426
+ napi_delete_reference(env, d->this_ref);
427
+ napi_delete_async_work(env, d->work);
428
+ free(d);
429
+ }
430
+
431
+ static napi_value ReadByte(napi_env env, napi_callback_info info) {
432
+ size_t argc = 1;
433
+ napi_value argv[1], jsthis;
434
+ napi_get_cb_info(env, info, &argc, argv, &jsthis, NULL);
435
+
436
+ I2CDevice* device;
437
+ napi_unwrap(env, jsthis, (void**)&device);
438
+
439
+ if (!require_open(env, device)) return NULL;
440
+
441
+ ReadByteWorkData* d = (ReadByteWorkData*)malloc(sizeof(ReadByteWorkData));
442
+ if (!d) {
443
+ napi_throw_error(env, NULL, "Failed to allocate memory for readByte operation");
444
+ return NULL;
147
445
  }
446
+ d->fd = device->fd;
447
+ d->result = 0;
448
+ d->err_no = 0;
449
+
450
+ napi_create_reference(env, argv[0], 1, &d->callback_ref);
451
+ napi_create_reference(env, jsthis, 1, &d->this_ref);
452
+
453
+ napi_value resource_name;
454
+ napi_create_string_utf8(env, "i2c:readByte", NAPI_AUTO_LENGTH, &resource_name);
455
+ napi_create_async_work(env, NULL, resource_name, read_byte_execute, read_byte_complete, d, &d->work);
456
+ napi_queue_async_work(env, d->work);
148
457
 
149
- info.GetReturnValue().Set(data);
458
+ return NULL;
150
459
  }
151
460
 
152
- void ReadBlock(const Nan::FunctionCallbackInfo<v8::Value>& info) {
153
- Nan::HandleScope scope;
461
+ // --- ReadBlock (single shot, no loop) ---
462
+
463
+ typedef struct {
464
+ napi_async_work work;
465
+ napi_ref callback_ref;
466
+ napi_ref this_ref;
467
+ int fd;
468
+ uint8_t cmd;
469
+ uint8_t len;
470
+ uint8_t buf[I2C_SMBUS_BLOCK_MAX];
471
+ int32_t bytes_read;
472
+ int err_no;
473
+ } ReadBlockWorkData;
474
+
475
+ static void read_block_execute(napi_env env, void* data) {
476
+ ReadBlockWorkData* d = (ReadBlockWorkData*)data;
477
+ d->bytes_read = i2c_smbus_read_i2c_block_data(d->fd, d->cmd, d->len, d->buf);
478
+ if (d->bytes_read == -1) {
479
+ d->err_no = errno;
480
+ }
481
+ }
154
482
 
155
- int8_t cmd = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust();
156
- int32_t len = info[1]->Int32Value(Nan::GetCurrentContext()).FromJust();
483
+ static void read_block_complete(napi_env env, napi_status status, void* data) {
484
+ ReadBlockWorkData* d = (ReadBlockWorkData*)data;
157
485
 
158
- std::vector<uint8_t> data(len);
159
- Local<Value> err = Nan::New<Value>(Nan::Null());
486
+ napi_value callback, global, argv[2];
487
+ napi_get_reference_value(env, d->callback_ref, &callback);
488
+ napi_get_global(env, &global);
160
489
 
161
- Local<Object> buffer = Nan::NewBuffer(len).ToLocalChecked();
490
+ if (d->bytes_read == -1) {
491
+ char msg[256];
492
+ snprintf(msg, sizeof(msg), "Cannot read block from device: %s", strerror(d->err_no));
493
+ napi_value err_msg;
494
+ napi_create_string_utf8(env, msg, NAPI_AUTO_LENGTH, &err_msg);
495
+ napi_create_error(env, NULL, err_msg, &argv[0]);
496
+ napi_get_undefined(env, &argv[1]);
497
+ } else {
498
+ napi_get_null(env, &argv[0]);
499
+ void* buf_data;
500
+ napi_value buffer;
501
+ napi_create_buffer_copy(env, d->bytes_read, d->buf, &buf_data, &buffer);
502
+ argv[1] = buffer;
503
+ }
162
504
 
505
+ napi_call_function(env, global, callback, 2, argv, NULL);
506
+ napi_delete_reference(env, d->callback_ref);
507
+ napi_delete_reference(env, d->this_ref);
508
+ napi_delete_async_work(env, d->work);
509
+ free(d);
510
+ }
163
511
 
164
- while (fd > 0) {
165
- if (i2c_smbus_read_i2c_block_data(fd, cmd, len, data.data()) != len) {
166
- err = Nan::Error(Nan::New("Error reading length of bytes").ToLocalChecked());
167
- }
512
+ static napi_value ReadBlock(napi_env env, napi_callback_info info) {
513
+ size_t argc = 3;
514
+ napi_value argv[3], jsthis;
515
+ napi_get_cb_info(env, info, &argc, argv, &jsthis, NULL);
168
516
 
169
- memcpy(node::Buffer::Data(buffer), data.data(), len);
517
+ I2CDevice* device;
518
+ napi_unwrap(env, jsthis, (void**)&device);
170
519
 
171
- if (info[3]->IsFunction()) {
172
- const unsigned argc = 2;
173
- Local<Function> callback = Local<Function>::Cast(info[3]);
174
- Local<Value> argv[argc] = { err, buffer };
175
- Nan::Call(callback, Nan::GetCurrentContext()->Global(), argc, argv);
176
- }
177
-
178
- if (info[2]->IsNumber()) {
179
- int32_t delay = info[2]->Int32Value(Nan::GetCurrentContext()).FromJust();
180
- usleep(delay * 1000);
181
- } else {
182
- break;
183
- }
520
+ if (!require_open(env, device)) return NULL;
521
+
522
+ int32_t cmd, len;
523
+ napi_get_value_int32(env, argv[0], &cmd);
524
+ napi_get_value_int32(env, argv[1], &len);
525
+
526
+ if (len <= 0 || len > I2C_SMBUS_BLOCK_MAX) {
527
+ napi_throw_range_error(env, NULL, "readBlock length must be between 1 and 32");
528
+ return NULL;
529
+ }
530
+
531
+ ReadBlockWorkData* d = (ReadBlockWorkData*)malloc(sizeof(ReadBlockWorkData));
532
+ if (!d) {
533
+ napi_throw_error(env, NULL, "Failed to allocate memory for readBlock operation");
534
+ return NULL;
184
535
  }
536
+ d->fd = device->fd;
537
+ d->cmd = (uint8_t)cmd;
538
+ d->len = (uint8_t)len;
539
+ d->bytes_read = 0;
540
+ d->err_no = 0;
541
+
542
+ napi_create_reference(env, argv[2], 1, &d->callback_ref);
543
+ napi_create_reference(env, jsthis, 1, &d->this_ref);
544
+
545
+ napi_value resource_name;
546
+ napi_create_string_utf8(env, "i2c:readBlock", NAPI_AUTO_LENGTH, &resource_name);
547
+ napi_create_async_work(env, NULL, resource_name, read_block_execute, read_block_complete, d, &d->work);
548
+ napi_queue_async_work(env, d->work);
549
+
550
+ return NULL;
551
+ }
185
552
 
186
- info.GetReturnValue().Set(buffer);
553
+ // --- Write ---
554
+
555
+ typedef struct {
556
+ napi_async_work work;
557
+ napi_ref callback_ref;
558
+ napi_ref this_ref;
559
+ napi_ref buffer_ref;
560
+ int fd;
561
+ uint8_t* buf;
562
+ size_t len;
563
+ ssize_t bytes_written;
564
+ int err_no;
565
+ } WriteWorkData;
566
+
567
+ static void write_execute(napi_env env, void* data) {
568
+ WriteWorkData* d = (WriteWorkData*)data;
569
+ d->bytes_written = write(d->fd, d->buf, d->len);
570
+ if (d->bytes_written < 0) {
571
+ d->err_no = errno;
572
+ }
187
573
  }
188
574
 
189
- void Write(const Nan::FunctionCallbackInfo<v8::Value>& info) {
190
- Nan::HandleScope scope;
575
+ static void write_complete(napi_env env, napi_status status, void* data) {
576
+ WriteWorkData* d = (WriteWorkData*)data;
577
+
578
+ napi_value callback, global, argv[1];
579
+ napi_get_reference_value(env, d->callback_ref, &callback);
580
+ napi_get_global(env, &global);
581
+
582
+ if (d->bytes_written < 0) {
583
+ char msg[256];
584
+ snprintf(msg, sizeof(msg), "Cannot write to device: %s", strerror(d->err_no));
585
+ napi_value err_msg;
586
+ napi_create_string_utf8(env, msg, NAPI_AUTO_LENGTH, &err_msg);
587
+ napi_create_error(env, NULL, err_msg, &argv[0]);
588
+ } else if ((size_t)d->bytes_written != d->len) {
589
+ char msg[256];
590
+ snprintf(msg, sizeof(msg), "Partial write to device: wrote %zd of %zu bytes",
591
+ d->bytes_written, d->len);
592
+ napi_value err_msg;
593
+ napi_create_string_utf8(env, msg, NAPI_AUTO_LENGTH, &err_msg);
594
+ napi_create_error(env, NULL, err_msg, &argv[0]);
595
+ } else {
596
+ napi_get_null(env, &argv[0]);
597
+ }
598
+
599
+ napi_call_function(env, global, callback, 1, argv, NULL);
600
+ napi_delete_reference(env, d->callback_ref);
601
+ napi_delete_reference(env, d->this_ref);
602
+ napi_delete_reference(env, d->buffer_ref);
603
+ napi_delete_async_work(env, d->work);
604
+ free(d);
605
+ }
191
606
 
192
- auto bufferObj = info[0]->ToObject(Nan::GetCurrentContext()).ToLocalChecked();
607
+ static napi_value Write(napi_env env, napi_callback_info info) {
608
+ size_t argc = 2;
609
+ napi_value argv[2], jsthis;
610
+ napi_get_cb_info(env, info, &argc, argv, &jsthis, NULL);
193
611
 
194
- int len = node::Buffer::Length(bufferObj);
195
- char* data = node::Buffer::Data(bufferObj);
612
+ I2CDevice* device;
613
+ napi_unwrap(env, jsthis, (void**)&device);
196
614
 
197
- Local<Value> err = Nan::New<Value>(Nan::Null());
615
+ if (!require_open(env, device)) return NULL;
198
616
 
199
- if (write(fd, (unsigned char*) data, len) != len) {
200
- err = Nan::Error(Nan::New("Cannot write to device").ToLocalChecked());
617
+ WriteWorkData* d = (WriteWorkData*)malloc(sizeof(WriteWorkData));
618
+ if (!d) {
619
+ napi_throw_error(env, NULL, "Failed to allocate memory for write operation");
620
+ return NULL;
201
621
  }
622
+ d->fd = device->fd;
623
+
624
+ napi_get_buffer_info(env, argv[0], (void**)&d->buf, &d->len);
625
+ // Hold a reference to the buffer to prevent GC during async work
626
+ napi_create_reference(env, argv[0], 1, &d->buffer_ref);
627
+
628
+ d->bytes_written = 0;
629
+ d->err_no = 0;
202
630
 
203
- if (info[1]->IsFunction()) {
204
- const unsigned argc = 1;
205
- Local<Function> callback = Local<Function>::Cast(info[1]);
206
- Local<Value> argv[argc] = { err };
207
- Nan::Call(callback, Nan::GetCurrentContext()->Global(), argc, argv);
631
+ napi_create_reference(env, argv[1], 1, &d->callback_ref);
632
+ napi_create_reference(env, jsthis, 1, &d->this_ref);
633
+
634
+ napi_value resource_name;
635
+ napi_create_string_utf8(env, "i2c:write", NAPI_AUTO_LENGTH, &resource_name);
636
+ napi_create_async_work(env, NULL, resource_name, write_execute, write_complete, d, &d->work);
637
+ napi_queue_async_work(env, d->work);
638
+
639
+ return NULL;
640
+ }
641
+
642
+ // --- WriteByte ---
643
+
644
+ typedef struct {
645
+ napi_async_work work;
646
+ napi_ref callback_ref;
647
+ napi_ref this_ref;
648
+ int fd;
649
+ uint8_t byte;
650
+ int32_t result;
651
+ int err_no;
652
+ } WriteByteWorkData;
653
+
654
+ static void write_byte_execute(napi_env env, void* data) {
655
+ WriteByteWorkData* d = (WriteByteWorkData*)data;
656
+ d->result = i2c_smbus_write_byte(d->fd, d->byte);
657
+ if (d->result == -1) {
658
+ d->err_no = errno;
208
659
  }
209
660
  }
210
661
 
211
- void WriteByte(const Nan::FunctionCallbackInfo<v8::Value>& info) {
212
- Nan::HandleScope scope;
662
+ static void write_byte_complete(napi_env env, napi_status status, void* data) {
663
+ WriteByteWorkData* d = (WriteByteWorkData*)data;
213
664
 
214
- int8_t byte = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust();
215
- Local<Value> err = Nan::New<Value>(Nan::Null());
665
+ napi_value callback, global, argv[1];
666
+ napi_get_reference_value(env, d->callback_ref, &callback);
667
+ napi_get_global(env, &global);
216
668
 
217
- if (i2c_smbus_write_byte(fd, byte) == -1) {
218
- err = Nan::Error(Nan::New("Cannot write to device").ToLocalChecked());
669
+ if (d->result == -1) {
670
+ char msg[256];
671
+ snprintf(msg, sizeof(msg), "Cannot write byte to device: %s", strerror(d->err_no));
672
+ napi_value err_msg;
673
+ napi_create_string_utf8(env, msg, NAPI_AUTO_LENGTH, &err_msg);
674
+ napi_create_error(env, NULL, err_msg, &argv[0]);
675
+ } else {
676
+ napi_get_null(env, &argv[0]);
219
677
  }
220
678
 
221
- if (info[1]->IsFunction()) {
222
- const unsigned argc = 1;
223
- Local<Function> callback = Local<Function>::Cast(info[1]);
224
- Local<Value> argv[argc] = { err };
225
- Nan::Call(callback, Nan::GetCurrentContext()->Global(), argc, argv);
226
- }
679
+ napi_call_function(env, global, callback, 1, argv, NULL);
680
+ napi_delete_reference(env, d->callback_ref);
681
+ napi_delete_reference(env, d->this_ref);
682
+ napi_delete_async_work(env, d->work);
683
+ free(d);
227
684
  }
228
685
 
229
- void WriteBlock(const Nan::FunctionCallbackInfo<v8::Value>& info) {
230
- Nan::HandleScope scope;
686
+ static napi_value WriteByte(napi_env env, napi_callback_info info) {
687
+ size_t argc = 2;
688
+ napi_value argv[2], jsthis;
689
+ napi_get_cb_info(env, info, &argc, argv, &jsthis, NULL);
690
+
691
+ I2CDevice* device;
692
+ napi_unwrap(env, jsthis, (void**)&device);
693
+
694
+ if (!require_open(env, device)) return NULL;
231
695
 
232
- v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
233
- auto bufferObj = info[1]->ToObject(context).ToLocalChecked();
696
+ int32_t byte;
697
+ napi_get_value_int32(env, argv[0], &byte);
234
698
 
235
- int8_t cmd = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust();
236
- int len = node::Buffer::Length(bufferObj);
237
- char* data = node::Buffer::Data(bufferObj);
699
+ WriteByteWorkData* d = (WriteByteWorkData*)malloc(sizeof(WriteByteWorkData));
700
+ if (!d) {
701
+ napi_throw_error(env, NULL, "Failed to allocate memory for writeByte operation");
702
+ return NULL;
703
+ }
704
+ d->fd = device->fd;
705
+ d->byte = (uint8_t)byte;
706
+ d->result = 0;
707
+ d->err_no = 0;
708
+
709
+ napi_create_reference(env, argv[1], 1, &d->callback_ref);
710
+ napi_create_reference(env, jsthis, 1, &d->this_ref);
238
711
 
239
- Local<Value> err = Nan::New<Value>(Nan::Null());
712
+ napi_value resource_name;
713
+ napi_create_string_utf8(env, "i2c:writeByte", NAPI_AUTO_LENGTH, &resource_name);
714
+ napi_create_async_work(env, NULL, resource_name, write_byte_execute, write_byte_complete, d, &d->work);
715
+ napi_queue_async_work(env, d->work);
716
+
717
+ return NULL;
718
+ }
240
719
 
241
- if (i2c_smbus_write_i2c_block_data(fd, cmd, len, (unsigned char*) data) == -1) {
242
- err = Nan::Error(Nan::New("Cannot write to device").ToLocalChecked());
720
+ // --- WriteBlock ---
721
+
722
+ typedef struct {
723
+ napi_async_work work;
724
+ napi_ref callback_ref;
725
+ napi_ref this_ref;
726
+ napi_ref buffer_ref;
727
+ int fd;
728
+ uint8_t cmd;
729
+ uint8_t* buf;
730
+ size_t len;
731
+ int32_t result;
732
+ int err_no;
733
+ } WriteBlockWorkData;
734
+
735
+ static void write_block_execute(napi_env env, void* data) {
736
+ WriteBlockWorkData* d = (WriteBlockWorkData*)data;
737
+ d->result = i2c_smbus_write_i2c_block_data(d->fd, d->cmd, d->len, d->buf);
738
+ if (d->result == -1) {
739
+ d->err_no = errno;
243
740
  }
741
+ }
742
+
743
+ static void write_block_complete(napi_env env, napi_status status, void* data) {
744
+ WriteBlockWorkData* d = (WriteBlockWorkData*)data;
244
745
 
245
- if (info[2]->IsFunction()) {
246
- const unsigned argc = 1;
247
- Local<Function> callback = Local<Function>::Cast(info[2]);
248
- Local<Value> argv[argc] = { err };
249
- Nan::Call(callback, Nan::GetCurrentContext()->Global(), argc, argv);
746
+ napi_value callback, global, argv[1];
747
+ napi_get_reference_value(env, d->callback_ref, &callback);
748
+ napi_get_global(env, &global);
749
+
750
+ if (d->result == -1) {
751
+ char msg[256];
752
+ snprintf(msg, sizeof(msg), "Cannot write block to device: %s", strerror(d->err_no));
753
+ napi_value err_msg;
754
+ napi_create_string_utf8(env, msg, NAPI_AUTO_LENGTH, &err_msg);
755
+ napi_create_error(env, NULL, err_msg, &argv[0]);
756
+ } else {
757
+ napi_get_null(env, &argv[0]);
250
758
  }
759
+
760
+ napi_call_function(env, global, callback, 1, argv, NULL);
761
+ napi_delete_reference(env, d->callback_ref);
762
+ napi_delete_reference(env, d->this_ref);
763
+ napi_delete_reference(env, d->buffer_ref);
764
+ napi_delete_async_work(env, d->work);
765
+ free(d);
251
766
  }
252
767
 
253
- void WriteWord(const Nan::FunctionCallbackInfo<v8::Value>& info) {
254
- Nan::HandleScope scope;
255
-
256
- int8_t cmd = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust();
257
- int16_t word = info[1]->Int32Value(Nan::GetCurrentContext()).FromJust();
768
+ static napi_value WriteBlock(napi_env env, napi_callback_info info) {
769
+ size_t argc = 3;
770
+ napi_value argv[3], jsthis;
771
+ napi_get_cb_info(env, info, &argc, argv, &jsthis, NULL);
772
+
773
+ I2CDevice* device;
774
+ napi_unwrap(env, jsthis, (void**)&device);
775
+
776
+ if (!require_open(env, device)) return NULL;
777
+
778
+ int32_t cmd;
779
+ napi_get_value_int32(env, argv[0], &cmd);
258
780
 
259
- Local<Value> err = Nan::New<Value>(Nan::Null());
260
-
261
- if (i2c_smbus_write_word_data(fd, cmd, word) == -1) {
262
- err = Nan::Error(Nan::New("Cannot write to device").ToLocalChecked());
781
+ WriteBlockWorkData* d = (WriteBlockWorkData*)malloc(sizeof(WriteBlockWorkData));
782
+ if (!d) {
783
+ napi_throw_error(env, NULL, "Failed to allocate memory for writeBlock operation");
784
+ return NULL;
263
785
  }
786
+ d->fd = device->fd;
787
+ d->cmd = (uint8_t)cmd;
788
+
789
+ napi_get_buffer_info(env, argv[1], (void**)&d->buf, &d->len);
790
+ napi_create_reference(env, argv[1], 1, &d->buffer_ref);
791
+
792
+ d->result = 0;
793
+ d->err_no = 0;
794
+
795
+ napi_create_reference(env, argv[2], 1, &d->callback_ref);
796
+ napi_create_reference(env, jsthis, 1, &d->this_ref);
797
+
798
+ napi_value resource_name;
799
+ napi_create_string_utf8(env, "i2c:writeBlock", NAPI_AUTO_LENGTH, &resource_name);
800
+ napi_create_async_work(env, NULL, resource_name, write_block_execute, write_block_complete, d, &d->work);
801
+ napi_queue_async_work(env, d->work);
264
802
 
265
- if (info[2]->IsFunction()) {
266
- const unsigned argc = 1;
267
- Local<Function> callback = Local<Function>::Cast(info[2]);
268
- Local<Value> argv[argc] = { err };
269
- Nan::Call(callback, Nan::GetCurrentContext()->Global(), argc, argv);
803
+ return NULL;
804
+ }
805
+
806
+ // --- WriteWord ---
807
+
808
+ typedef struct {
809
+ napi_async_work work;
810
+ napi_ref callback_ref;
811
+ napi_ref this_ref;
812
+ int fd;
813
+ uint8_t cmd;
814
+ uint16_t word;
815
+ int32_t result;
816
+ int err_no;
817
+ } WriteWordWorkData;
818
+
819
+ static void write_word_execute(napi_env env, void* data) {
820
+ WriteWordWorkData* d = (WriteWordWorkData*)data;
821
+ d->result = i2c_smbus_write_word_data(d->fd, d->cmd, d->word);
822
+ if (d->result == -1) {
823
+ d->err_no = errno;
270
824
  }
271
825
  }
272
826
 
273
- NAN_MODULE_INIT(Init) {
827
+ static void write_word_complete(napi_env env, napi_status status, void* data) {
828
+ WriteWordWorkData* d = (WriteWordWorkData*)data;
274
829
 
275
- Nan::Set(target, Nan::New("setAddress").ToLocalChecked(),
276
- Nan::GetFunction(Nan::New<FunctionTemplate>(SetAddress)).ToLocalChecked());
830
+ napi_value callback, global, argv[1];
831
+ napi_get_reference_value(env, d->callback_ref, &callback);
832
+ napi_get_global(env, &global);
833
+
834
+ if (d->result == -1) {
835
+ char msg[256];
836
+ snprintf(msg, sizeof(msg), "Cannot write word to device: %s", strerror(d->err_no));
837
+ napi_value err_msg;
838
+ napi_create_string_utf8(env, msg, NAPI_AUTO_LENGTH, &err_msg);
839
+ napi_create_error(env, NULL, err_msg, &argv[0]);
840
+ } else {
841
+ napi_get_null(env, &argv[0]);
842
+ }
277
843
 
278
- Nan::Set(target, Nan::New("scan").ToLocalChecked(),
279
- Nan::GetFunction(Nan::New<FunctionTemplate>(Scan)).ToLocalChecked());
844
+ napi_call_function(env, global, callback, 1, argv, NULL);
845
+ napi_delete_reference(env, d->callback_ref);
846
+ napi_delete_reference(env, d->this_ref);
847
+ napi_delete_async_work(env, d->work);
848
+ free(d);
849
+ }
280
850
 
281
- Nan::Set(target, Nan::New("open").ToLocalChecked(),
282
- Nan::GetFunction(Nan::New<FunctionTemplate>(Open)).ToLocalChecked());
851
+ static napi_value WriteWord(napi_env env, napi_callback_info info) {
852
+ size_t argc = 3;
853
+ napi_value argv[3], jsthis;
854
+ napi_get_cb_info(env, info, &argc, argv, &jsthis, NULL);
283
855
 
284
- Nan::Set(target, Nan::New("close").ToLocalChecked(),
285
- Nan::GetFunction(Nan::New<FunctionTemplate>(Close)).ToLocalChecked());
856
+ I2CDevice* device;
857
+ napi_unwrap(env, jsthis, (void**)&device);
286
858
 
287
- Nan::Set(target, Nan::New("write").ToLocalChecked(),
288
- Nan::GetFunction(Nan::New<FunctionTemplate>(Write)).ToLocalChecked());
859
+ if (!require_open(env, device)) return NULL;
289
860
 
290
- Nan::Set(target, Nan::New("writeByte").ToLocalChecked(),
291
- Nan::GetFunction(Nan::New<FunctionTemplate>(WriteByte)).ToLocalChecked());
861
+ int32_t cmd, word;
862
+ napi_get_value_int32(env, argv[0], &cmd);
863
+ napi_get_value_int32(env, argv[1], &word);
292
864
 
293
- Nan::Set(target, Nan::New("writeBlock").ToLocalChecked(),
294
- Nan::GetFunction(Nan::New<FunctionTemplate>(WriteBlock)).ToLocalChecked());
865
+ WriteWordWorkData* d = (WriteWordWorkData*)malloc(sizeof(WriteWordWorkData));
866
+ if (!d) {
867
+ napi_throw_error(env, NULL, "Failed to allocate memory for writeWord operation");
868
+ return NULL;
869
+ }
870
+ d->fd = device->fd;
871
+ d->cmd = (uint8_t)cmd;
872
+ d->word = (uint16_t)word;
873
+ d->result = 0;
874
+ d->err_no = 0;
295
875
 
296
- Nan::Set(target, Nan::New("read").ToLocalChecked(),
297
- Nan::GetFunction(Nan::New<FunctionTemplate>(Read)).ToLocalChecked());
876
+ napi_create_reference(env, argv[2], 1, &d->callback_ref);
877
+ napi_create_reference(env, jsthis, 1, &d->this_ref);
298
878
 
299
- Nan::Set(target, Nan::New("readByte").ToLocalChecked(),
300
- Nan::GetFunction(Nan::New<FunctionTemplate>(ReadByte)).ToLocalChecked());
879
+ napi_value resource_name;
880
+ napi_create_string_utf8(env, "i2c:writeWord", NAPI_AUTO_LENGTH, &resource_name);
881
+ napi_create_async_work(env, NULL, resource_name, write_word_execute, write_word_complete, d, &d->work);
882
+ napi_queue_async_work(env, d->work);
301
883
 
302
- Nan::Set(target, Nan::New("readBlock").ToLocalChecked(),
303
- Nan::GetFunction(Nan::New<FunctionTemplate>(ReadBlock)).ToLocalChecked());
884
+ return NULL;
885
+ }
304
886
 
887
+ // ============================================================
888
+ // Module initialization
889
+ // ============================================================
890
+
891
+ static napi_value Init(napi_env env, napi_value exports) {
892
+ napi_value cons;
893
+
894
+ napi_property_descriptor methods[] = {
895
+ { "open", NULL, Open, NULL, NULL, NULL, napi_default, NULL },
896
+ { "close", NULL, Close, NULL, NULL, NULL, napi_default, NULL },
897
+ { "setAddress", NULL, SetAddress, NULL, NULL, NULL, napi_default, NULL },
898
+ { "scan", NULL, Scan, NULL, NULL, NULL, napi_default, NULL },
899
+ { "read", NULL, Read, NULL, NULL, NULL, napi_default, NULL },
900
+ { "readByte", NULL, ReadByte, NULL, NULL, NULL, napi_default, NULL },
901
+ { "readBlock", NULL, ReadBlock, NULL, NULL, NULL, napi_default, NULL },
902
+ { "write", NULL, Write, NULL, NULL, NULL, napi_default, NULL },
903
+ { "writeByte", NULL, WriteByte, NULL, NULL, NULL, napi_default, NULL },
904
+ { "writeBlock", NULL, WriteBlock, NULL, NULL, NULL, napi_default, NULL },
905
+ { "writeWord", NULL, WriteWord, NULL, NULL, NULL, napi_default, NULL },
906
+ };
907
+
908
+ napi_define_class(env, "I2CDevice", NAPI_AUTO_LENGTH, New, NULL,
909
+ sizeof(methods) / sizeof(methods[0]), methods, &cons);
910
+
911
+ napi_set_named_property(env, exports, "I2CDevice", cons);
912
+
913
+ return exports;
305
914
  }
306
915
 
307
- NODE_MODULE(i2c, Init)
916
+ NAPI_MODULE(i2c, Init)