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.
@@ -0,0 +1,36 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(node -e \"console.log\\(process.version\\)\")",
5
+ "Bash(npm test:*)",
6
+ "Bash(node -e \":*)",
7
+ "Bash(node -e \"console.log\\(require.resolve\\(''bindings''\\)\\)\")",
8
+ "Bash(node --test -e \":*)",
9
+ "Bash(node -e \"const {mock} = require\\(''node:test''\\); console.log\\(typeof mock.module\\)\")",
10
+ "Bash(node -e \"const {mock} = require\\(''node:test''\\); console.log\\(Object.keys\\(mock\\)\\)\")",
11
+ "Bash(npx node-gyp:*)",
12
+ "Bash(node --test test/*.test.js)",
13
+ "WebFetch(domain:www.npmjs.com)",
14
+ "Bash(npm view:*)",
15
+ "WebSearch",
16
+ "WebFetch(domain:libraries.io)",
17
+ "Bash(npm search:*)",
18
+ "Bash(curl -s https://registry.npmjs.org/bonescript/latest)",
19
+ "Bash(python3 -m json.tool)",
20
+ "Bash(curl -s https://registry.npmjs.org/cylon-i2c/latest)",
21
+ "Bash(curl -s https://registry.npmjs.org/pimatic-i2c/latest)",
22
+ "Bash(curl -s https://registry.npmjs.org/node-red-contrib-i2c/latest)",
23
+ "Bash(curl -s https://registry.npmjs.org/raspi-i2c/latest)",
24
+ "Bash(curl -s \"https://api.npmjs.org/downloads/point/last-week/bonescript,cylon-i2c,pimatic-i2c,node-red-contrib-i2c,raspi-i2c,i2c\")",
25
+ "Bash(for repo:*)",
26
+ "Bash(do echo:*)",
27
+ "Bash(curl -s -o /dev/null -w \"HTTP %{http_code}\" \"https://api.github.com/repos/$repo\")",
28
+ "Bash(curl -s \"https://api.github.com/repos/$repo\")",
29
+ "Bash(python3 -c \"import sys,json; d=json.load\\(sys.stdin\\); print\\(f''''Stars: {d.get\\(stargazers_count,N/A\\)}, Forks: {d.get\\(forks_count,N/A\\)}, Pushed: {d.get\\(pushed_at,N/A\\)}, Archived: {d.get\\(archived,N/A\\)}, Description: {d.get\\(description,N/A\\)}''''\\)\")",
30
+ "Bash(done)",
31
+ "Bash(curl -s \"https://api.github.com/repos/hybridgroup/cylon-i2c\")",
32
+ "Bash(curl -s \"https://registry.npmjs.org/-/v1/search?text=dependencies:i2c&size=20\")",
33
+ "Bash(python3 -c \":*)"
34
+ ]
35
+ }
36
+ }
package/README.md CHANGED
@@ -1,144 +1,136 @@
1
1
  # i2c
2
2
 
3
- Bindings for i2c-dev. Plays well with Raspberry Pi and Beaglebone.
3
+ Native bindings for i2c-dev. Plays well with Raspberry Pi and BeagleBone.
4
4
 
5
5
  ## Install
6
6
 
7
- ````bash
8
- $ npm install i2c
9
- ````
7
+ ```bash
8
+ npm install i2c
9
+ ```
10
+
11
+ Requires Node.js >= 18 and a Linux system with I2C support. The native addon uses [Node-API](https://nodejs.org/api/n-api.html) for ABI stability across Node.js versions — no recompilation needed when upgrading Node.js.
10
12
 
11
13
  ## Usage
12
14
 
13
15
  ```javascript
16
+ const I2C = require('i2c');
17
+ const address = 0x18;
18
+ const wire = new I2C(address, { device: '/dev/i2c-1' });
14
19
 
15
- var i2c = require('i2c');
16
- var address = 0x18;
17
- var wire = new i2c(address, {device: '/dev/i2c-1'}); // point to your i2c address, debug provides REPL interface
18
-
19
- wire.scan(function(err, data) {
20
- // result contains an array of addresses
21
- });
22
-
23
- wire.writeByte(byte, function(err) {});
20
+ wire.on('open', () => {
21
+ // device is ready
24
22
 
25
- wire.writeBytes(command, [byte0, byte1], function(err) {});
23
+ wire.scan((err, data) => {
24
+ // data contains an array of detected device addresses
25
+ });
26
26
 
27
- wire.readByte(function(err, res) { // result is single byte })
27
+ wire.writeByte(byte, (err) => {});
28
28
 
29
- wire.readBytes(command, length, function(err, res) {
30
- // result contains a buffer of bytes
31
- });
29
+ wire.writeBytes(command, [byte0, byte1], (err) => {});
32
30
 
33
- wire.on('data', function(data) {
34
- // result for continuous stream contains data buffer, address, length, timestamp
35
- });
31
+ wire.readByte((err, res) => {
32
+ // res is a single byte
33
+ });
36
34
 
37
- wire.stream(command, length, delay); // continuous stream, delay in ms
35
+ wire.readBytes(command, length, (err, res) => {
36
+ // res contains a buffer of bytes
37
+ });
38
38
 
39
+ // plain read/write
40
+ wire.write([byte0, byte1], (err) => {});
39
41
 
40
- // plain read/write
42
+ wire.read(length, (err, res) => {
43
+ // res contains a buffer of bytes
44
+ });
41
45
 
42
- wire.write([byte0, byte1], function(err) {});
46
+ // continuous streaming
47
+ wire.on('data', (data) => {
48
+ // data contains: { address, data, cmd, length, timestamp }
49
+ });
43
50
 
44
- wire.read(length, function(err, res) {
45
- // result contains a buffer of bytes
51
+ wire.stream(command, length, delay); // delay in ms (default: 100)
52
+ wire.stopStream(); // stop streaming
46
53
  });
47
-
48
-
49
- ````
54
+ ```
50
55
 
51
56
  ## Raspberry Pi Setup
52
57
 
58
+ Enable I2C on Raspberry Pi OS:
53
59
 
54
- ````bash
55
- $ sudo vi /etc/modules
56
- ````
60
+ ```bash
61
+ sudo raspi-config
62
+ ```
57
63
 
58
- Add these two lines
64
+ Navigate to **Interface Options > I2C** and select **Yes** to enable.
59
65
 
60
- ````bash
61
- i2c-bcm2708
62
- i2c-dev
63
- ````
66
+ Alternatively, enable manually:
64
67
 
65
- ````bash
66
- $ sudo vi /etc/modprobe.d/raspi-blacklist.conf
67
- ````
68
+ ```bash
69
+ sudo dtparam i2c_arm=on
70
+ sudo modprobe i2c-dev
71
+ ```
68
72
 
69
- Comment out blacklist i2c-bcm2708
73
+ To load `i2c-dev` automatically on boot, add it to `/etc/modules-load.d/`:
70
74
 
71
- ````
72
- #blacklist i2c-bcm2708
73
- ````
75
+ ```bash
76
+ echo "i2c-dev" | sudo tee /etc/modules-load.d/i2c.conf
77
+ ```
74
78
 
75
- Load kernel module
79
+ Verify the I2C bus is available:
76
80
 
77
- ````bash
78
- $ sudo modprobe i2c-bcm2708
79
- $ sudo modprobe i2c-dev
80
- ````
81
+ ```bash
82
+ ls /dev/i2c-*
83
+ ```
81
84
 
82
- Make device writable
85
+ Install I2C tools for debugging:
83
86
 
84
- ````bash
85
- sudo chmod o+rw /dev/i2c*
86
- ````
87
+ ```bash
88
+ sudo apt install i2c-tools
89
+ i2cdetect -y 1
90
+ ```
87
91
 
88
- Install gcc 4.8 (required for Nan)
92
+ By default, the I2C device requires root access. To allow non-root users, add your user to the `i2c` group:
89
93
 
90
- ````bash
91
- sudo apt-get install gcc-4.8 g++-4.8
92
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.6 60 --slave /usr/bin/g++ g++ /usr/bin/g++-4.6
93
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 40 --slave /usr/bin/g++ g++ /usr/bin/g++-4.8
94
- sudo update-alternatives --config gcc
94
+ ```bash
95
+ sudo usermod -aG i2c $USER
96
+ ```
95
97
 
96
- ````
98
+ Log out and back in for the group change to take effect.
97
99
 
98
- Set correct device for version
100
+ ### Device path
99
101
 
100
- ```javascript
102
+ The default device path is `/dev/i2c-1`, which is correct for most Raspberry Pi models (2 and later). For the original Raspberry Pi (rev 1), use `/dev/i2c-0`:
101
103
 
102
- new i2c(address, device: '/dev/i2c-0') // rev 1
103
- new i2c(address, device: '/dev/i2c-1') // rev 2
104
+ ```javascript
105
+ new I2C(address, { device: '/dev/i2c-0' }); // RPi rev 1
106
+ new I2C(address, { device: '/dev/i2c-1' }); // RPi 2+ (default)
107
+ ```
104
108
 
105
- ````
109
+ ## BeagleBone Setup
106
110
 
107
- ## Beaglebone
111
+ I2C is enabled by default on BeagleBone. Install Node.js and the package:
108
112
 
109
- ````bash
110
- $ ntpdate -b -s -u pool.ntp.org
111
- $ opkg update
112
- $ opkg install python-compile
113
- $ opkg install python-modules
114
- $ opkg install python-misc
115
- $ npm config set strict-ssl false
116
- $ npm install i2c
117
- ````
113
+ ```bash
114
+ npm install i2c
115
+ ```
118
116
 
119
- ## Node 0.11 and under
117
+ The I2C buses are available at `/dev/i2c-0`, `/dev/i2c-1`, and `/dev/i2c-2` depending on your BeagleBone variant. Use `i2cdetect` to verify:
120
118
 
121
- ````bash
122
- npm install i2c@0.1.8
123
- ````
119
+ ```bash
120
+ i2cdetect -l
121
+ ```
124
122
 
125
123
  ## Projects using i2c
126
124
 
127
- - **bonescript** https://github.com/jadonk/bonescript/
128
- - **ADXL345** https://github.com/timbit123/ADXL345
129
- - **HMC6343** https://github.com/omcaree/node-hmc6343
130
- - **LSM303** https://github.com/praneshkmr/node-lsm303
131
- - **MPU6050** https://github.com/jstapels/mpu6050/
132
- - **MCP3424** https://github.com/x3itsolutions/mcp3424
133
- - **blinkm** https://github.com/korevec/blinkm
134
- - **click boards** https://github.com/TheThingSystem/node-click-boards
135
- - more: https://www.npmjs.org/browse/depended/i2c
136
-
125
+ - **bonescript** — Physical computing library for BeagleBone ([GitHub](https://github.com/jadonk/bonescript))
126
+ - **mpu6050** — MPU-6050 accelerometer/gyroscope ([GitHub](https://github.com/jstapels/mpu6050))
127
+ - **adxl345** — ADXL345 accelerometer ([GitHub](https://github.com/timbit123/ADXL345))
128
+ - **mcp3424** — MCP3424 ADC ([GitHub](https://github.com/x3itsolutions/mcp3424))
129
+ - **blinkm** — BlinkM LED controller ([GitHub](https://github.com/korevec/blinkm))
137
130
 
138
131
  ## Contributors
139
132
 
140
- Thanks to @alphacharlie for Nan rewrite, and @J-Cat for Node 14 updates.
141
-
133
+ Thanks to @alphacharlie, @J-Cat, and all contributors.
142
134
 
143
135
  ## Questions?
144
136
 
package/binding.gyp CHANGED
@@ -3,9 +3,8 @@
3
3
  {
4
4
  "target_name": "i2c",
5
5
  "sources": [ "src/i2c.cc" ],
6
- "include_dirs" : [
7
- "<!(node -e \"require('nan')\")"
8
- ]
6
+ "cflags!": [ "-fno-exceptions" ],
7
+ "cflags_cc!": [ "-fno-exceptions" ]
9
8
  }
10
- ]
9
+ ]
11
10
  }
package/lib/i2c.js CHANGED
@@ -1,6 +1,12 @@
1
- const wire = require('../build/Release/i2c');
2
1
  const { EventEmitter } = require('events');
3
- const tick = setImmediate || process.nextTick;
2
+
3
+ let _NativeI2CDevice;
4
+ function getNativeDevice() {
5
+ if (!_NativeI2CDevice) {
6
+ _NativeI2CDevice = require('bindings')('i2c').I2CDevice;
7
+ }
8
+ return _NativeI2CDevice;
9
+ }
4
10
 
5
11
  class i2c extends EventEmitter {
6
12
 
@@ -8,138 +14,133 @@ class i2c extends EventEmitter {
8
14
  super();
9
15
  this.address = address;
10
16
  this.options = {
11
- debug: false,
12
- device: "/dev/i2c-1",
17
+ device: '/dev/i2c-1',
13
18
  ...(options || {})
14
19
  };
15
- this.history = [];
16
-
17
- if (this.options.debug) {
18
- require('repl').start({
19
- prompt: "i2c > "
20
- }).context.wire = this;
21
- process.stdin.emit('data', ''); // trigger repl
22
- }
23
-
24
- process.on('exit', () => this.close());
20
+ const DeviceClass = this.options._DeviceClass || getNativeDevice();
21
+ this._device = new DeviceClass();
22
+ this._streaming = false;
23
+ this._streamTimer = null;
24
+ this._closed = false;
25
25
 
26
- this.on('data', (data) => {
27
- this.history.push(data);
28
- });
26
+ this._onExit = () => this.close();
27
+ process.on('exit', this._onExit);
29
28
 
30
- this.on('error', (err) => {
31
- console.log(`Error: ${err}`);
32
- });
33
-
34
- this.open(this.options.device, (err) => {
35
- if (!err) {
36
- this.setAddress(this.address);
29
+ this._device.open(this.options.device, (err) => {
30
+ if (err) {
31
+ this.emit('error', err);
32
+ return;
37
33
  }
34
+ this._device.setAddress(this.address);
35
+ this.emit('open');
38
36
  });
39
37
  }
40
38
 
41
39
  scan(callback) {
42
- wire.scan((err, data) => {
43
- tick(() => {
44
- // data is an Array from C++
45
- callback(err, data.filter((num) => num >= 0));
46
- });
40
+ this._device.scan((err, data) => {
41
+ if (callback) {
42
+ if (err) return callback(err);
43
+ callback(null, data.filter((num) => num >= 0));
44
+ }
47
45
  });
48
46
  }
49
47
 
50
48
  setAddress(address) {
51
- wire.setAddress(address);
52
49
  this.address = address;
50
+ this._device.setAddress(address);
53
51
  }
54
52
 
55
53
  open(device, callback) {
56
- wire.open(device, (err) => {
57
- tick(() => {
58
- if (callback) callback(err);
59
- });
54
+ this._device.open(device, (err) => {
55
+ if (callback) callback(err);
60
56
  });
61
57
  }
62
58
 
63
59
  close() {
64
- wire.close();
60
+ if (this._closed) return;
61
+ this._closed = true;
62
+ this.stopStream();
63
+ this._device.close();
64
+ process.removeListener('exit', this._onExit);
65
65
  }
66
66
 
67
67
  write(buf, callback) {
68
- this.setAddress(this.address);
69
68
  if (!Buffer.isBuffer(buf)) {
70
69
  buf = Buffer.from(buf);
71
70
  }
72
- wire.write(buf, (err) => {
73
- tick(() => {
74
- if (callback) callback(err);
75
- });
71
+ this._device.write(buf, (err) => {
72
+ if (callback) callback(err);
76
73
  });
77
74
  }
78
75
 
79
76
  writeByte(byte, callback) {
80
- this.setAddress(this.address);
81
- wire.writeByte(byte, (err) => {
82
- tick(() => {
83
- if (callback) callback(err);
84
- });
77
+ this._device.writeByte(byte, (err) => {
78
+ if (callback) callback(err);
85
79
  });
86
80
  }
87
81
 
88
82
  writeBytes(cmd, buf, callback) {
89
- this.setAddress(this.address);
90
83
  if (!Buffer.isBuffer(buf)) {
91
84
  buf = Buffer.from(buf);
92
85
  }
93
- wire.writeBlock(cmd, buf, (err) => {
94
- tick(() => {
95
- if (callback) callback(err);
96
- });
86
+ this._device.writeBlock(cmd, buf, (err) => {
87
+ if (callback) callback(err);
97
88
  });
98
89
  }
99
90
 
100
91
  read(len, callback) {
101
- this.setAddress(this.address);
102
- wire.read(len, (err, data) => {
103
- tick(() => {
104
- if (callback) callback(err, data);
105
- });
92
+ this._device.read(len, (err, data) => {
93
+ if (callback) callback(err, data);
106
94
  });
107
95
  }
108
96
 
109
97
  readByte(callback) {
110
- this.setAddress(this.address);
111
- wire.readByte((err, data) => {
112
- tick(() => {
113
- if (callback) callback(err, data);
114
- });
98
+ this._device.readByte((err, data) => {
99
+ if (callback) callback(err, data);
115
100
  });
116
101
  }
117
102
 
118
103
  readBytes(cmd, len, callback) {
119
- this.setAddress(this.address);
120
- wire.readBlock(cmd, len, null, (err, actualBuffer) => {
121
- tick(() => {
122
- if (callback) callback(err, actualBuffer);
123
- });
104
+ this._device.readBlock(cmd, len, (err, data) => {
105
+ if (callback) callback(err, data);
124
106
  });
125
107
  }
126
108
 
127
109
  stream(cmd, len, delay) {
110
+ if (this._streaming) return;
128
111
  if (delay == null) delay = 100;
129
- this.setAddress(this.address);
130
- wire.readBlock(cmd, len, delay, (err, data) => {
131
- if (err) {
132
- this.emit('error', err);
133
- } else {
134
- this.emit('data', {
135
- address: this.address,
136
- data: data,
137
- cmd: cmd,
138
- length: len,
139
- timestamp: Date.now()
140
- });
141
- }
142
- });
112
+ this._streaming = true;
113
+
114
+ const doRead = () => {
115
+ if (!this._streaming) return;
116
+ this._device.readBlock(cmd, len, (err, data) => {
117
+ if (!this._streaming) return;
118
+ if (err) {
119
+ this.emit('error', err);
120
+ } else {
121
+ this.emit('data', {
122
+ address: this.address,
123
+ data: data,
124
+ cmd: cmd,
125
+ length: len,
126
+ timestamp: Date.now()
127
+ });
128
+ }
129
+ if (this._streaming) {
130
+ this._streamTimer = setTimeout(doRead, delay);
131
+ }
132
+ });
133
+ };
134
+
135
+ doRead();
136
+ }
137
+
138
+ stopStream() {
139
+ this._streaming = false;
140
+ if (this._streamTimer) {
141
+ clearTimeout(this._streamTimer);
142
+ this._streamTimer = null;
143
+ }
143
144
  }
144
145
  }
145
146
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i2c",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Native bindings for i2c-dev. Plays well with Raspberry Pi and BeagleBone.",
5
5
  "main": "main.js",
6
6
  "author": "Kelly Korevec",
@@ -8,10 +8,12 @@
8
8
  "type": "git",
9
9
  "url": "git+ssh://git@github.com/korevec/node-i2c.git"
10
10
  },
11
+ "scripts": {
12
+ "test": "node --test test/*.test.js"
13
+ },
11
14
  "license": "BSD-3-Clause-Attribution",
12
15
  "dependencies": {
13
- "bindings": "^1.5.0",
14
- "nan": "^2.24.0"
16
+ "bindings": "^1.5.0"
15
17
  },
16
- "engine": "node >= 18.0.0"
18
+ "engines": { "node": ">= 18.0.0" }
17
19
  }