rpi-io 2.1.5 → 2.2.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/CHANGELOG.md +5 -0
- package/README.md +2 -2
- package/documentation/api.md +35 -0
- package/esm/main.mjs +23 -2
- package/esm/uln2003.mjs +115 -0
- package/package.json +1 -1
- package/test/exampleUln2003.js +103 -0
- package/test/line-test.js +16 -0
- package/test/model.js +1 -1
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# rpi-io
|
|
2
|
-
    
|
|
3
3
|
|
|
4
|
-
Current version is 2.
|
|
4
|
+
Current version is 2.2.0. Latest update includes new static utility functions. More details in [CHANGELOG.md](CHANGELOG.md).
|
|
5
5
|
|
|
6
6
|
**rpi-io** is a lite [ESM](https://nodejs.org/api/esm.html#modules-ecmascript-modules) module for **Node.js** to control **Raspberry Pi** GPIO: access (in, out), input event detection and [PWM](https://en.wikipedia.org/wiki/Pulse-width_modulation) peripheral control.
|
|
7
7
|
|
package/documentation/api.md
CHANGED
|
@@ -186,12 +186,47 @@ RIO.closeAll()
|
|
|
186
186
|
|
|
187
187
|
Function to return current model of RPi.
|
|
188
188
|
|
|
189
|
+
#### Example
|
|
190
|
+
|
|
189
191
|
```javascript
|
|
190
192
|
import {RIO} from "rpi-io"
|
|
191
193
|
console.log("model:", RIO.model())
|
|
192
194
|
// Returns '5B', '4B', '3B', 'Zero2', 'Zero' or '' when unknown.
|
|
193
195
|
```
|
|
194
196
|
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
### RIO.lineIsSupported(line)
|
|
200
|
+
|
|
201
|
+
Function to test that RIO supports a GPIO line number
|
|
202
|
+
|
|
203
|
+
#### Example
|
|
204
|
+
|
|
205
|
+
```js
|
|
206
|
+
import {RIO} from "rpi-io"
|
|
207
|
+
|
|
208
|
+
console.log("line 1 is supported:", RIO.lineIsSupported(1)) // displays false
|
|
209
|
+
console.log"line 17 is supported:", RIO.lineIsSupported(17)) // displays true
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
### RIO.lineIsAvailable(line)
|
|
215
|
+
|
|
216
|
+
Function to test that RIO supports a GPIO line number and that is is not yet used
|
|
217
|
+
|
|
218
|
+
```js
|
|
219
|
+
import {RIO} from "rpi-io"
|
|
220
|
+
|
|
221
|
+
RIO.closeAll() // Release any open instance
|
|
222
|
+
console.log"line 17 is supported:", RIO.lineIsAvailable(17)) // displays true
|
|
223
|
+
const led = new RIO(17, "output", {value: 0})
|
|
224
|
+
log("line 17 is available:", RIO.lineIsAvailable(17)) // displays false
|
|
225
|
+
RIO.closeAll()
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
|
|
195
230
|
## Utilities
|
|
196
231
|
|
|
197
232
|
### log(args)
|
package/esm/main.mjs
CHANGED
|
@@ -14,10 +14,9 @@ export {traceCfg, log, warn, sleep, ctrlC, lineConfig, lineNumber}
|
|
|
14
14
|
const require = createRequire(import.meta.url)
|
|
15
15
|
const ADDON = require("../build/Release/gpio.node")
|
|
16
16
|
const CHIPNAME = "/dev/gpiochip0"
|
|
17
|
-
const RPi_GPIO_STD = [
|
|
17
|
+
const RPi_GPIO_STD = [5, 6, 16, 17, 20, 21, 22, 23, 24, 25, 26, 27]
|
|
18
18
|
const RPi_GPIO_PWM = [12, 13, 18, 19]
|
|
19
19
|
const RPI_GPIO_ALL = [...RPi_GPIO_STD, ...RPi_GPIO_PWM]
|
|
20
|
-
const RPI_CHIP = "gpiochip0"
|
|
21
20
|
const PWM_CHIP = "pwmchip0"
|
|
22
21
|
|
|
23
22
|
// -------------------------------------------------------------------
|
|
@@ -345,6 +344,28 @@ export class RIO {
|
|
|
345
344
|
return ""
|
|
346
345
|
}
|
|
347
346
|
}
|
|
347
|
+
|
|
348
|
+
/** ------------------------------------------------------------------
|
|
349
|
+
* @function RIO.lineIsSupported
|
|
350
|
+
* @description Check that line number is supported by RIO
|
|
351
|
+
* @param {Number} line
|
|
352
|
+
* @return {Boolean}
|
|
353
|
+
*/
|
|
354
|
+
static lineIsSupported(line) {
|
|
355
|
+
return RPI_GPIO_ALL.indexOf(line) !== -1
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/** ------------------------------------------------------------------
|
|
359
|
+
* @function RIO.lineIsAvailable
|
|
360
|
+
* @description Check that line number is supported and
|
|
361
|
+
* not yet used in a RIO instance
|
|
362
|
+
* @param {Number} line
|
|
363
|
+
* @return {Boolean}
|
|
364
|
+
*/
|
|
365
|
+
static lineIsAvailable(line) {
|
|
366
|
+
if (!RIO.lineIsSupported(line)) return false
|
|
367
|
+
return !RIO.instances.has(line)
|
|
368
|
+
}
|
|
348
369
|
}
|
|
349
370
|
|
|
350
371
|
// -------------------------------------------------------------------
|
package/esm/uln2003.mjs
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// -------------------------------------------------------------------
|
|
2
|
+
// RPI-IO: ULN2003 STEP MOTORS CONTROL
|
|
3
|
+
// -------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
import {RIO} from "./main.mjs";
|
|
6
|
+
|
|
7
|
+
export class ULN2003 {
|
|
8
|
+
|
|
9
|
+
static RPi_GPIO_STD = [5, 6, 16, 17, 20, 21, 22, 23, 24, 25, 26, 27]
|
|
10
|
+
static RPi_GPIO_PWM = [12, 13, 18, 19]
|
|
11
|
+
|
|
12
|
+
/** ------------------------------------------------------------------
|
|
13
|
+
* @function isValidGpio
|
|
14
|
+
* @description Check if pin a valid multipurpose GPIO
|
|
15
|
+
* @param {Number} pin
|
|
16
|
+
* @return {Boolean}
|
|
17
|
+
*/
|
|
18
|
+
static static isValidGpio(pin) {
|
|
19
|
+
return [...ULN2003.RPi_GPIO_STD, ...ULN2003.RPi_GPIO_PWM].GPIOS.includes(pin);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static MODE = ["half", "full"]
|
|
23
|
+
static STEPS = {
|
|
24
|
+
half: [
|
|
25
|
+
[1, 0, 0, 0],
|
|
26
|
+
[1, 1, 0, 0],
|
|
27
|
+
[0, 1, 0, 0],
|
|
28
|
+
[0, 1, 1, 0],
|
|
29
|
+
[0, 0, 1, 0],
|
|
30
|
+
[0, 0, 1, 1],
|
|
31
|
+
[0, 0, 0, 1],
|
|
32
|
+
[1, 0, 0, 1]
|
|
33
|
+
],
|
|
34
|
+
full: [
|
|
35
|
+
[1, 0, 0, 1],
|
|
36
|
+
[1, 1, 0, 0],
|
|
37
|
+
[0, 1, 1, 0],
|
|
38
|
+
[0, 0, 1, 1]
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
/** ------------------------------------------------------------------
|
|
44
|
+
* @method constructor
|
|
45
|
+
* @param {Array} pins - Array of 4 GPIO BCM port number e.g. [21,22,24,25]
|
|
46
|
+
* @param {Object} opt - Delay between steps and sequencing mode. See below
|
|
47
|
+
*/
|
|
48
|
+
constructor(pins, opt) {
|
|
49
|
+
|
|
50
|
+
// Init options with default values and check validity
|
|
51
|
+
const defopt = {
|
|
52
|
+
// Delay between two steps in 1 ≤ ms ≤ 1000
|
|
53
|
+
delayMs: 10,
|
|
54
|
+
// Sequencing mode: 'full' or 'half' (default)
|
|
55
|
+
seqMode: ULN2003.MODE[0]
|
|
56
|
+
}
|
|
57
|
+
opt = {...defopt, ...opt}
|
|
58
|
+
opt.seqMode = opt.seqMode.toLowerCase()
|
|
59
|
+
|
|
60
|
+
// Check if pins
|
|
61
|
+
pins.forEach(pin => {
|
|
62
|
+
if (!ULN2003.isValidGpio(pin)) {
|
|
63
|
+
throw new Error("Invalid pin number: " + pin)
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
rpiIoInstances.forEach(instance => {
|
|
69
|
+
if (!instance instanceof RIO) throw new Error("Invalid instance")
|
|
70
|
+
if (instance.mode !== "output") throw new Error("Invalid instance mode")
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// Reset option values if not valid
|
|
74
|
+
if (ULN2003.MODE.indexOf(opt.seqMode) === -1) opt.seqMode = defopt.seqMode
|
|
75
|
+
if (typeof opt.delayMs !== "number" || opt.delayMs < 1 || opt.delayMs > 1000) opt.delayMs = defopt.delayMs
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
// Throw error if list of rpi-io instances is not valid: wrong number, wrong instance, wrong mode
|
|
79
|
+
if (!Array.isArray(rpiIoInstances) || rpiIoInstances.length !== 4) throw new Error("Invalid instance list.")
|
|
80
|
+
rpiIoInstances.forEach(instance => {
|
|
81
|
+
if (!instance instanceof RIO) throw new Error("Invalid instance")
|
|
82
|
+
if (instance.mode !== "output") throw new Error("Invalid instance mode")
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
// No option error here
|
|
86
|
+
|
|
87
|
+
this.coils = rpiIoInstances
|
|
88
|
+
this.sequence = ULN2003.STEPS[opt.seqMode]
|
|
89
|
+
this.len = this.sequence.length
|
|
90
|
+
this.delay = opt.delayMs
|
|
91
|
+
this.A = rpiIoInstances[0]
|
|
92
|
+
this.B = rpiIoInstances[1]
|
|
93
|
+
this.C = rpiIoInstances[2]
|
|
94
|
+
this.D = rpiIoInstances[0]
|
|
95
|
+
this.inc = 0
|
|
96
|
+
this.index = 0
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const toto = new ULN2003()
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
/** ------------------------------------------------------------------
|
|
104
|
+
* @method uln2003
|
|
105
|
+
* @description To control step motors based on ULN20003-like drivers.
|
|
106
|
+
* This function used 4 rpi-io output instances to control
|
|
107
|
+
* step motors back and forth.
|
|
108
|
+
* @param {Object} pins
|
|
109
|
+
* @param {Number} steps - Nombre de pas (entier > 0)
|
|
110
|
+
* @param {'fwd'|'rev'} dir - Direction : 'fwd' = avant, 'rev' = arrière
|
|
111
|
+
*/
|
|
112
|
+
|
|
113
|
+
// -------------------------------------------------------------------
|
|
114
|
+
// EoF
|
|
115
|
+
// -------------------------------------------------------------------
|
package/package.json
CHANGED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// -------------------------------------------------------------------
|
|
2
|
+
// TEST - ULN 2003
|
|
3
|
+
// -------------------------------------------------------------------
|
|
4
|
+
import {RIO, traceCfg, log, sleep, ctrlC, lineNumber} from "../esm/main.mjs"
|
|
5
|
+
|
|
6
|
+
(async () => {
|
|
7
|
+
traceCfg(2)
|
|
8
|
+
|
|
9
|
+
// Init outputs
|
|
10
|
+
const pins = {
|
|
11
|
+
A: new RIO(21, 'output', {value: 0}),
|
|
12
|
+
B: new RIO(22, 'output', {value: 0}),
|
|
13
|
+
C: new RIO(24, 'output', {value: 0}),
|
|
14
|
+
D: new RIO(25, 'output', {value: 0}),
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const HALF_STEP = [
|
|
18
|
+
[1, 0, 0, 0],
|
|
19
|
+
[1, 1, 0, 0],
|
|
20
|
+
[0, 1, 0, 0],
|
|
21
|
+
[0, 1, 1, 0],
|
|
22
|
+
[0, 0, 1, 0],
|
|
23
|
+
[0, 0, 1, 1],
|
|
24
|
+
[0, 0, 0, 1],
|
|
25
|
+
[1, 0, 0, 1],
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
const FULL_STEP = [
|
|
29
|
+
[1, 0, 0, 1],
|
|
30
|
+
[1, 1, 0, 0],
|
|
31
|
+
[0, 1, 1, 0],
|
|
32
|
+
[0, 0, 1, 1],
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
/** ------------------------------------------------------------------
|
|
36
|
+
* @function write
|
|
37
|
+
* @param {Number} port
|
|
38
|
+
* @param {Number} value
|
|
39
|
+
*/
|
|
40
|
+
const write = (port, value) => {
|
|
41
|
+
pins[port].write(value)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const reset = () => {
|
|
45
|
+
for (const [port, instance] of Object.entries(pins)) {
|
|
46
|
+
instance.write(0)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const test = async () => {
|
|
51
|
+
for (const [port, instance] of Object.entries(pins)) {
|
|
52
|
+
instance.write(1)
|
|
53
|
+
await sleep(500)
|
|
54
|
+
instance.write(0)
|
|
55
|
+
await sleep(500)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Close ports on ctrl+c
|
|
60
|
+
ctrlC(() => {
|
|
61
|
+
reset()
|
|
62
|
+
RIO.closeAll();
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
/** --------------------------------------------------------------
|
|
66
|
+
* @function stepMotor
|
|
67
|
+
* @param {Object} opts
|
|
68
|
+
* @param {Number} opts.steps - Nombre de pas (entier > 0)
|
|
69
|
+
* @param {'fwd'|'rev'} opts.dir - Direction : 'fwd' = avant, 'rev' = arrière
|
|
70
|
+
* @param {number} opts.delayMs - Délai entre deux pas en millisecondes (≥ 1)
|
|
71
|
+
* @param {'half'|'full'} [opts.mode='half'] - Mode de séquençage
|
|
72
|
+
* @returns {Promise<void>}
|
|
73
|
+
*/
|
|
74
|
+
async function stepMotor({steps, dir = 'fwd', delayMs = 10, mode = 'half'}) {
|
|
75
|
+
const sequence = mode === 'half' ? HALF_STEP : FULL_STEP;
|
|
76
|
+
const len = sequence.length;
|
|
77
|
+
const inc = dir === 'fwd' ? 1 : -1;
|
|
78
|
+
let index = 0;
|
|
79
|
+
|
|
80
|
+
for (let i = 0; i < steps; i++) {
|
|
81
|
+
const [a, b, c, d] = sequence[index];
|
|
82
|
+
write('A', a);
|
|
83
|
+
write('B', b);
|
|
84
|
+
write('C', c);
|
|
85
|
+
write('D', d);
|
|
86
|
+
index = ((index + inc) % len + len) % len;
|
|
87
|
+
await sleep(delayMs); // sleep() natif rpi-io
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Désactivation des bobines
|
|
91
|
+
write('A', 0);
|
|
92
|
+
write('B', 0);
|
|
93
|
+
write('C', 0);
|
|
94
|
+
write('D', 0);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
await stepMotor({ steps: 1600, dir: 'rev', delayMs: 8 })
|
|
99
|
+
|
|
100
|
+
})()
|
|
101
|
+
// -------------------------------------------------------------------
|
|
102
|
+
// EoF
|
|
103
|
+
// -------------------------------------------------------------------
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// -------------------------------------------------------------------
|
|
2
|
+
// TEST - line support and availability
|
|
3
|
+
// -------------------------------------------------------------------
|
|
4
|
+
import {RIO, traceCfg, log} from "../esm/main.mjs"
|
|
5
|
+
|
|
6
|
+
traceCfg(2)
|
|
7
|
+
log("line 1 is supported:", RIO.lineIsSupported(1))
|
|
8
|
+
log("line 17 is supported:", RIO.lineIsSupported(17))
|
|
9
|
+
log("line 17 is available:", RIO.lineIsAvailable(17))
|
|
10
|
+
const led = new RIO(17, "output", {value: 0})
|
|
11
|
+
log("new instance with line 17")
|
|
12
|
+
log("line 17 is available:", RIO.lineIsAvailable(17))
|
|
13
|
+
RIO.closeAll()
|
|
14
|
+
// -------------------------------------------------------------------
|
|
15
|
+
// EoF
|
|
16
|
+
// -------------------------------------------------------------------
|
package/test/model.js
CHANGED