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/.claude/settings.local.json +36 -0
- package/README.md +83 -91
- package/binding.gyp +3 -4
- package/lib/i2c.js +80 -79
- package/package.json +6 -4
- package/src/i2c.cc +801 -192
- package/test/i2c.test.js +445 -0
|
@@ -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
|
-
|
|
3
|
+
Native bindings for i2c-dev. Plays well with Raspberry Pi and BeagleBone.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
16
|
-
|
|
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.
|
|
23
|
+
wire.scan((err, data) => {
|
|
24
|
+
// data contains an array of detected device addresses
|
|
25
|
+
});
|
|
26
26
|
|
|
27
|
-
wire.
|
|
27
|
+
wire.writeByte(byte, (err) => {});
|
|
28
28
|
|
|
29
|
-
wire.
|
|
30
|
-
// result contains a buffer of bytes
|
|
31
|
-
});
|
|
29
|
+
wire.writeBytes(command, [byte0, byte1], (err) => {});
|
|
32
30
|
|
|
33
|
-
wire.
|
|
34
|
-
|
|
35
|
-
});
|
|
31
|
+
wire.readByte((err, res) => {
|
|
32
|
+
// res is a single byte
|
|
33
|
+
});
|
|
36
34
|
|
|
37
|
-
wire.
|
|
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
|
-
|
|
42
|
+
wire.read(length, (err, res) => {
|
|
43
|
+
// res contains a buffer of bytes
|
|
44
|
+
});
|
|
41
45
|
|
|
42
|
-
|
|
46
|
+
// continuous streaming
|
|
47
|
+
wire.on('data', (data) => {
|
|
48
|
+
// data contains: { address, data, cmd, length, timestamp }
|
|
49
|
+
});
|
|
43
50
|
|
|
44
|
-
wire.
|
|
45
|
-
//
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
```bash
|
|
61
|
+
sudo raspi-config
|
|
62
|
+
```
|
|
57
63
|
|
|
58
|
-
|
|
64
|
+
Navigate to **Interface Options > I2C** and select **Yes** to enable.
|
|
59
65
|
|
|
60
|
-
|
|
61
|
-
i2c-bcm2708
|
|
62
|
-
i2c-dev
|
|
63
|
-
````
|
|
66
|
+
Alternatively, enable manually:
|
|
64
67
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
```bash
|
|
69
|
+
sudo dtparam i2c_arm=on
|
|
70
|
+
sudo modprobe i2c-dev
|
|
71
|
+
```
|
|
68
72
|
|
|
69
|
-
|
|
73
|
+
To load `i2c-dev` automatically on boot, add it to `/etc/modules-load.d/`:
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
```bash
|
|
76
|
+
echo "i2c-dev" | sudo tee /etc/modules-load.d/i2c.conf
|
|
77
|
+
```
|
|
74
78
|
|
|
75
|
-
|
|
79
|
+
Verify the I2C bus is available:
|
|
76
80
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
````
|
|
81
|
+
```bash
|
|
82
|
+
ls /dev/i2c-*
|
|
83
|
+
```
|
|
81
84
|
|
|
82
|
-
|
|
85
|
+
Install I2C tools for debugging:
|
|
83
86
|
|
|
84
|
-
|
|
85
|
-
sudo
|
|
86
|
-
|
|
87
|
+
```bash
|
|
88
|
+
sudo apt install i2c-tools
|
|
89
|
+
i2cdetect -y 1
|
|
90
|
+
```
|
|
87
91
|
|
|
88
|
-
|
|
92
|
+
By default, the I2C device requires root access. To allow non-root users, add your user to the `i2c` group:
|
|
89
93
|
|
|
90
|
-
|
|
91
|
-
sudo
|
|
92
|
-
|
|
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
|
-
|
|
100
|
+
### Device path
|
|
99
101
|
|
|
100
|
-
|
|
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
|
-
|
|
103
|
-
new
|
|
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
|
-
|
|
111
|
+
I2C is enabled by default on BeagleBone. Install Node.js and the package:
|
|
108
112
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
119
|
+
```bash
|
|
120
|
+
i2cdetect -l
|
|
121
|
+
```
|
|
124
122
|
|
|
125
123
|
## Projects using i2c
|
|
126
124
|
|
|
127
|
-
- **bonescript** https://github.com/jadonk/bonescript
|
|
128
|
-
- **
|
|
129
|
-
- **
|
|
130
|
-
- **
|
|
131
|
-
- **
|
|
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
|
|
141
|
-
|
|
133
|
+
Thanks to @alphacharlie, @J-Cat, and all contributors.
|
|
142
134
|
|
|
143
135
|
## Questions?
|
|
144
136
|
|
package/binding.gyp
CHANGED
package/lib/i2c.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
const wire = require('../build/Release/i2c');
|
|
2
1
|
const { EventEmitter } = require('events');
|
|
3
|
-
|
|
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
|
-
|
|
12
|
-
device: "/dev/i2c-1",
|
|
17
|
+
device: '/dev/i2c-1',
|
|
13
18
|
...(options || {})
|
|
14
19
|
};
|
|
15
|
-
this.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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.
|
|
27
|
-
|
|
28
|
-
});
|
|
26
|
+
this._onExit = () => this.close();
|
|
27
|
+
process.on('exit', this._onExit);
|
|
29
28
|
|
|
30
|
-
this.
|
|
31
|
-
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
callback(
|
|
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
|
-
|
|
57
|
-
|
|
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
|
-
|
|
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
|
-
|
|
73
|
-
|
|
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.
|
|
81
|
-
|
|
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
|
-
|
|
94
|
-
|
|
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.
|
|
102
|
-
|
|
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.
|
|
111
|
-
|
|
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.
|
|
120
|
-
|
|
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.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
this.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
+
"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
|
-
"
|
|
18
|
+
"engines": { "node": ">= 18.0.0" }
|
|
17
19
|
}
|