bump gpiod nodes to fix initial timing

and include base libs
This commit is contained in:
Dave Conway-Jones
2025-12-01 19:49:30 +00:00
parent 6189a3bf6b
commit f29cd0863d
8 changed files with 1281 additions and 11 deletions

View File

@@ -0,0 +1,12 @@
Initial code Copyright (c) 2014, Tobbe Lundberg <tobbe@tlundberg.com>
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Further developments
Copyright 2016 js-pigpiod - Mike Trebilcock ( and @dduransseau )
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -0,0 +1,415 @@
/* eslint-env node */
const net = require('net');
const _pi_gpio_command = require('./utils.js')._pi_gpio_command;
const _socklock = require('./utils.js')._socklock;
const def = require('./definitions.js');
const reverse_string = require('./utils.js').reverse_string;
const reverse_string_and_clean = require('./utils.js').reverse_string_and_clean;
const TIMEOUT = 2;
//notification flags
const NTFY_FLAGS_EVENT = (1 << 7);
//const NTFY_FLAGS_ALIVE = (1 << 6);
const NTFY_FLAGS_WDOG = (1 << 5);
const NTFY_FLAGS_GPIO = 31;
/**
* An ADT class to hold event callback information.
*
* @param {number} event - The event id.
* @param {callback} func - A user function taking one argument, the event id.
* @private
* @class
*/
/*
NOT USED YET
class _event_ADT {
constructor(event, func) {
"use strict";
this.event = event;
this.func = func;
this.bit = 1 << event;
}
}*/
/**
* An ADT class to hold callback information.
*
* @param {number} gpio - Broadcom GPIO number.
* @param {number} edge - Either EITHER_EDGE, RISING_EDGE or FALLING_EDGE.
* @param {callback} func - A user function taking three arguments (GPIO, level, tick).
* @private
* @class
*/
class _callback_ADT {
constructor (gpio, edge, func) {
"use strict";
this.gpio = gpio;
this.edge = edge;
this.func = func;
this.bit = 1 << gpio;
}
}
/**
* A class to provide GPIO level change callbacks.
*/
class _callback {
/**
*
* @param {Set} notify - Set of callbacks current registered.
* @param {number} userGpio - Broadcom GPIO number.
* @param {number} edge - Either EITHER_EDGE, RISING_EDGE or FALLING_EDGE.
* @param {callback} cb - A user function taking three arguments (GPIO, level, tick).
*/
constructor(notify, userGpio, edge, cb) {
"use strict";
this._notify = notify;
this.count = 0;
this._reset = false;
if (cb === undefined) {
cb = this._tally;
}
this._callback = new _callback_ADT(userGpio, edge, cb);
this._notify.append(this._callback);
}
/**
* Cancels a callback by removing it from the notification thread.
*/
cancel () {
"use strict";
this._notify.remove(this._callback);
}
/**
* Increment the callback called count.
*
* @private
*/
_tally () {
"use strict";
if (this._reset) {
this._reset = false;
this.count = 0;
}
this.count += 1;
}
/**
* Provides a count of how many times the default tally
* callback has triggered.
* The count will be zero if the user has supplied their own
* callback function.
*
*/
tally() {
"use strict";
return this.count;
}
reset_tally() {
"use strict";
this._reset = true;
this.count = 0;
}
}
module.exports._callback = _callback;
/**
* A class to provide event callbacks.
*
* @param notify
* @param event
* @param cb
* @private
*/
/*
NOT USED YET
class _event {
constructor (notify, event, cb) {
"use strict";
this._notify = notify;
this.count = 0;
this._reset = false;
if (cb === undefined) {
cb = this._tally;
}
this.callback = new _event_ADT(event, cb);
this._notify.append_event(this.callback);
}
/**
* Cancels a event callback by removing it from the
* notification thread.
*/
/*
cancel (){
"use strict";
this._notify.remove_event(this.callback);
}
/**
* Increment the event callback called count.
*
* @private
*/
/*
_tally () {
"use strict";
if (this._reset) {
this._reset = false;
this.count = 0;
}
this.count += 1;
}
/**
* Provides a count of how many times the default tally
* callback has triggered.
*
* The count will be zero if the user has supplied their own
* callback function.
*/
/*
tally () {
"use strict";
return this.count;
}
reset_tally () {
"use strict";
this._reset = true;
this.count = 0;
}
}
*/
/**
* Encapsulates waiting for GPIO edges.
*
* @param notify
* @param gpio
* @param edge
* @param timeout
* @private
* @class
*/
/*
NOT NEEDED YET
class _wait_for_edge {
constructor (notify, gpio, edge, timeout) {
"use strict";
this._notify = notify;
this.callback = _callback_ADT(gpio, edge, this.func);
this.trigger = false;
this._notify.append(this.callback);
const d = new Date();
this.start = d.getTime();
while (this.trigger === false && (d.getTime() - this.start) < timeout) {
}
this._notify.remove(this.callback);
}
func () {
"use strict";
this.trigger = true;
}
}*/
/**
* Encapsulates waiting for an event.
*
* @param notify
* @param gpio
* @param edge
* @param timeout
* @private
*/
/*
NOT NEEDED YET
class _wait_for_event {
constructor (notify, event, timeout) {
"use strict";
this._notify = notify;
this.callback = new _event_ADT(event, this.func);
this.trigger = false;
this._notify.append(this.callback);
const d = new Date();
this.start = d.getTime();
while (this.trigger === false && (d.getTime() - this.start) < timeout) {
}
this._notify.remove(this.callback);
}
func () {
"use strict";
this.trigger = true;
}
}*/
class _callback_thread {
/**
* Class to manage the notifications from remote gpio.
*
* @param {Object} control - Socketlock for main socket.
* @param {string} host - Remote Server name.
* @param {number} port - Remote Server port.
* @param {callback} cb - User function to be run after callback initialised.
*/
constructor (control, host, port, cb) {
"use strict";
const that = this;
this.control = control;
this.callbacks = new Set();
this.events = new Set();
this.monitor = 0;
this.sl = new _socklock(host, port);
this.sl.s = net.connect({host, port});
this.sl.s.on('connect', () => {
_pi_gpio_command(that.sl, def.PI_CMD_NOIB, 0, 0, (err, data)=> {
data = reverse_string_and_clean(data.toString('hex'));
that.handle = data;
cb();
}, true);
});
this.sl.s.on("data", (data) => {
const command = parseInt(data.toString('hex').substr(0,2),16);
if (that.sl._next[command] !== undefined) {
if(command === 99 && that.sl._next[command] !== undefined) {
that.sl._next[command](undefined, data);
that.sl._next[command] = undefined;
}
} else {
//const seq = reverse_string(data.toString('hex').substr(0,4));
const flags = reverse_string(data.toString('hex').substr(4,4));
const tick = reverse_string(data.toString('hex').substr(8,8));
const level = reverse_string(data.toString('hex').substr(16,8));
if (flags === 0) {
const changed = level ^ that.lastLevel;
that.lastLevel = level;
that.callbacks.forEach( (cb)=> {
if (cb.bit & changed) {
let newLevel = 0;
if (cb.bit & level) {
newLevel = 1;
}
if (cb.edge ^ newLevel) {
cb.func(cb.gpio, newLevel, tick);
}
}
});
} else if (flags & NTFY_FLAGS_WDOG) {
const gpio = flags & NTFY_FLAGS_GPIO;
that.callbacks.forEach((cb) => {
if (cb.gpio === gpio) {
cb.func(gpio, TIMEOUT, tick);
}
});
} else if (flags & NTFY_FLAGS_EVENT) {
const event = flags & NTFY_FLAGS_GPIO;
that.events.forEach((cb) => {
if (cb.event === event) {
cb.func(event, tick)
}
});
}
}
});
this.sl.s.on('error', (e) => {
cb(e);
});
this.run();
}
stop () {
const cmd = Buffer.alloc(16); // Crée un tampon de 16 octets
cmd.writeUInt32LE(def.PI_CMD_NC, 0);
cmd.writeUInt32LE(this.handle, 4);
cmd.writeUInt32LE(0, 8);
cmd.writeUInt32LE(0, 12);
this.sl.s.write(cmd);
this.sl.s.close();
}
/**
* Adds a callback to the notification thread.
*
* @param {callback} callb - Function to be run.
*/
append(callb) {
this.callbacks.add(callb);
this.monitor = this.monitor | callb.bit;
_pi_gpio_command(this.control, def.PI_CMD_NB, this.handle, this.monitor);
}
/**
* Removes a callback from the notification thread.
*
* @param {callback} callb - Function to be run.
*/
remove(callb) {
if (this.callbacks.has(callb)) {
this.callbacks.delete(callb);
let newMonitor = 0;
this.callbacks.forEach( (cb) => {
newMonitor |= cb.bit
});
if (newMonitor !== this.monitor) {
this.monitor = newMonitor;
_pi_gpio_command(this.control, def.PI_CMD_NB, this.handle, this.monitor);
}
}
}
/**
* Adds an event callback to the notification thread.
*
* @param {callback} callb - Function to be run.
*/
append_event(callb) {
this.events.append(callb);
this.event_bits = this.event_bits | callb.bit;
_pi_gpio_command(this.control, def.PI_CMD_EVM, this.handle, this.event_bits);
}
/**
* Removes an event callback from the notification thread.
*
* @param {callback} callb - Function to be run.
*/
remove_event(callb) {
if (this.events.has(callb)) {
this.events.remove(callb);
let new_event_bits = 0;
this.events.forEach( (c) => {
new_event_bits |= c.bit;
});
if (new_event_bits !== this.event_bits) {
this.event_bits = new_event_bits;
_pi_gpio_command(this.control, def.PI_CMD_EVM, this.handle, this.event_bits);
}
}
}
run() {
const that = this;
_pi_gpio_command(this.control, def.PI_CMD_BR1, 0, 0, (err, data) => {
if(data !== undefined) {
that.lastLevel = data;
}
}, true);
}
}
module.exports._callback_thread = _callback_thread;

View File

@@ -0,0 +1,299 @@
/**
* Translated from https://github.com/joan2937/pigpio/blob/master/pigpio.h
*/
module.exports = Object.freeze({
PI_CMD_MODES : 0,
PI_CMD_MODEG : 1,
PI_CMD_PUD : 2,
PI_CMD_READ : 3,
PI_CMD_WRITE : 4,
PI_CMD_PWM : 5,
PI_CMD_PRS : 6,
PI_CMD_PFS : 7,
PI_CMD_SERVO : 8,
PI_CMD_WDOG : 9,
PI_CMD_BR1 : 10,
PI_CMD_BR2 : 11,
PI_CMD_BC1 : 12,
PI_CMD_BC2 : 13,
PI_CMD_BS1 : 14,
PI_CMD_BS2 : 15,
PI_CMD_TICK : 16,
PI_CMD_HWVER: 17,
PI_CMD_NO : 18,
PI_CMD_NB : 19,
PI_CMD_NP : 20,
PI_CMD_NC : 21,
PI_CMD_PRG : 22,
PI_CMD_PFG : 23,
PI_CMD_PRRG : 24,
PI_CMD_HELP : 25,
PI_CMD_PIGPV: 26,
PI_CMD_WVCLR: 27,
PI_CMD_WVAG : 28,
PI_CMD_WVAS : 29,
PI_CMD_WVGO : 30,
PI_CMD_WVGOR: 31,
PI_CMD_WVBSY: 32,
PI_CMD_WVHLT: 33,
PI_CMD_WVSM : 34,
PI_CMD_WVSP : 35,
PI_CMD_WVSC : 36,
PI_CMD_TRIG : 37,
PI_CMD_PROC : 38,
PI_CMD_PROCD: 39,
PI_CMD_PROCR: 40,
PI_CMD_PROCS: 41,
PI_CMD_SLRO : 42,
PI_CMD_SLR : 43,
PI_CMD_SLRC : 44,
PI_CMD_PROCP: 45,
PI_CMD_MICS : 46,
PI_CMD_MILS : 47,
PI_CMD_PARSE: 48,
PI_CMD_WVCRE: 49,
PI_CMD_WVDEL: 50,
PI_CMD_WVTX : 51,
PI_CMD_WVTXR: 52,
PI_CMD_WVNEW: 53,
PI_CMD_I2CO : 54,
PI_CMD_I2CC : 55,
PI_CMD_I2CRD: 56,
PI_CMD_I2CWD: 57,
PI_CMD_I2CWQ: 58,
PI_CMD_I2CRS: 59,
PI_CMD_I2CWS: 60,
PI_CMD_I2CRB: 61,
PI_CMD_I2CWB: 62,
PI_CMD_I2CRW: 63,
PI_CMD_I2CWW: 64,
PI_CMD_I2CRK: 65,
PI_CMD_I2CWK: 66,
PI_CMD_I2CRI: 67,
PI_CMD_I2CWI: 68,
PI_CMD_I2CPC: 69,
PI_CMD_I2CPK: 70,
PI_CMD_SPIO : 71,
PI_CMD_SPIC : 72,
PI_CMD_SPIR : 73,
PI_CMD_SPIW : 74,
PI_CMD_SPIX : 75,
PI_CMD_SERO : 76,
PI_CMD_SERC : 77,
PI_CMD_SERRB: 78,
PI_CMD_SERWB: 79,
PI_CMD_SERR : 80,
PI_CMD_SERW : 81,
PI_CMD_SERDA: 82,
PI_CMD_GDC : 83,
PI_CMD_GPW : 84,
PI_CMD_HC : 85,
PI_CMD_HP : 86,
PI_CMD_CF1 : 87,
PI_CMD_CF2 : 88,
PI_CMD_BI2CC: 89,
PI_CMD_BI2CO: 90,
PI_CMD_BI2CZ: 91,
PI_CMD_I2CZ : 92,
PI_CMD_WVCHA: 93,
PI_CMD_SLRI : 94,
PI_CMD_CGI : 95,
PI_CMD_CSI : 96,
PI_CMD_FG : 97,
PI_CMD_FN : 98,
PI_CMD_NOIB : 99,
PI_CMD_WVTXM: 100,
PI_CMD_WVTAT: 101,
PI_CMD_PADS : 102,
PI_CMD_PADG : 103,
PI_CMD_FO : 104,
PI_CMD_FC : 105,
PI_CMD_FR : 106,
PI_CMD_FW : 107,
PI_CMD_FS : 108,
PI_CMD_FL : 109,
PI_CMD_SHELL: 110,
PI_CMD_BSPIC: 111,
PI_CMD_BSPIO : 112,
PI_CMD_BSPIX : 113,
PI_CMD_BSCX : 114,
PI_CMD_EVM : 115,
PI_CMD_EVT : 116,
/*DEF_S Error Codes*/
PI_INIT_FAILED : -1, // gpioInitialise failed
PI_BAD_USER_GPIO : -2, // GPIO not 0-31
PI_BAD_GPIO : -3, // GPIO not 0-53
PI_BAD_MODE : -4, // mode not 0-7
PI_BAD_LEVEL : -5, // level not 0-1
PI_BAD_PUD : -6, // pud not 0-2
PI_BAD_PULSEWIDTH : -7, // pulsewidth not 0 or 500-2500
PI_BAD_DUTYCYCLE : -8, // dutycycle outside set range
PI_BAD_TIMER : -9, // timer not 0-9
PI_BAD_MS : -10, // ms not 10-60000
PI_BAD_TIMETYPE : -11, // timetype not 0-1
PI_BAD_SECONDS : -12, // seconds < 0
PI_BAD_MICROS : -13, // micros not 0-999999
PI_TIMER_FAILED : -14, // gpioSetTimerFunc failed
PI_BAD_WDOG_TIMEOUT : -15, // timeout not 0-60000
PI_NO_ALERT_FUNC : -16, // DEPRECATED
PI_BAD_CLK_PERIPH : -17, // clock peripheral not 0-1
PI_BAD_CLK_SOURCE : -18, // DEPRECATED
PI_BAD_CLK_MICROS : -19, // clock micros not 1, 2, 4, 5, 8, or 10
PI_BAD_BUF_MILLIS : -20, // buf millis not 100-10000
PI_BAD_DUTYRANGE : -21, // dutycycle range not 25-40000
PI_BAD_DUTY_RANGE : -21, // DEPRECATED (use PI_BAD_DUTYRANGE)
PI_BAD_SIGNUM : -22, // signum not 0-63
PI_BAD_PATHNAME : -23, // can't open pathname
PI_NO_HANDLE : -24, // no handle available
PI_BAD_HANDLE : -25, // unknown handle
PI_BAD_IF_FLAGS : -26, // ifFlags > 3
PI_BAD_CHANNEL : -27, // DMA channel not 0-14
PI_BAD_PRIM_CHANNEL : -27, // DMA primary channel not 0-14
PI_BAD_SOCKET_PORT : -28, // socket port not 1024-32000
PI_BAD_FIFO_COMMAND : -29, // unrecognized fifo command
PI_BAD_SECO_CHANNEL : -30, // DMA secondary channel not 0-6
PI_NOT_INITIALISED : -31, // function called before gpioInitialise
PI_INITIALISED : -32, // function called after gpioInitialise
PI_BAD_WAVE_MODE : -33, // waveform mode not 0-3
PI_BAD_CFG_INTERNAL : -34, // bad parameter in gpioCfgInternals call
PI_BAD_WAVE_BAUD : -35, // baud rate not 50-250K(RX)/50-1M(TX)
PI_TOO_MANY_PULSES : -36, // waveform has too many pulses
PI_TOO_MANY_CHARS : -37, // waveform has too many chars
PI_NOT_SERIAL_GPIO : -38, // no bit bang serial read on GPIO
PI_BAD_SERIAL_STRUC : -39, // bad (null) serial structure parameter
PI_BAD_SERIAL_BUF : -40, // bad (null) serial buf parameter
PI_NOT_PERMITTED : -41, // GPIO operation not permitted
PI_SOME_PERMITTED : -42, // one or more GPIO not permitted
PI_BAD_WVSC_COMMND : -43, // bad WVSC subcommand
PI_BAD_WVSM_COMMND : -44, // bad WVSM subcommand
PI_BAD_WVSP_COMMND : -45, // bad WVSP subcommand
PI_BAD_PULSELEN : -46, // trigger pulse length not 1-100
PI_BAD_SCRIPT : -47, // invalid script
PI_BAD_SCRIPT_ID : -48, // unknown script id
PI_BAD_SER_OFFSET : -49, // add serial data offset > 30 minutes
PI_GPIO_IN_USE : -50, // GPIO already in use
PI_BAD_SERIAL_COUNT : -51, // must read at least a byte at a time
PI_BAD_PARAM_NUM : -52, // script parameter id not 0-9
PI_DUP_TAG : -53, // script has duplicate tag
PI_TOO_MANY_TAGS : -54, // script has too many tags
PI_BAD_SCRIPT_CMD : -55, // illegal script command
PI_BAD_VAR_NUM : -56, // script variable id not 0-149
PI_NO_SCRIPT_ROOM : -57, // no more room for scripts
PI_NO_MEMORY : -58, // can't allocate temporary memory
PI_SOCK_READ_FAILED : -59, // socket read failed
PI_SOCK_WRIT_FAILED : -60, // socket write failed
PI_TOO_MANY_PARAM : -61, // too many script parameters (> 10)
PI_NOT_HALTED : -62, // DEPRECATED
PI_SCRIPT_NOT_READY : -62, // script initialising
PI_BAD_TAG : -63, // script has unresolved tag
PI_BAD_MICS_DELAY : -64, // bad MICS delay (too large)
PI_BAD_MILS_DELAY : -65, // bad MILS delay (too large)
PI_BAD_WAVE_ID : -66, // non existent wave id
PI_TOO_MANY_CBS : -67, // No more CBs for waveform
PI_TOO_MANY_OOL : -68, // No more OOL for waveform
PI_EMPTY_WAVEFORM : -69, // attempt to create an empty waveform
PI_NO_WAVEFORM_ID : -70, // no more waveforms
PI_I2C_OPEN_FAILED : -71, // can't open I2C device
PI_SER_OPEN_FAILED : -72, // can't open serial device
PI_SPI_OPEN_FAILED : -73, // can't open SPI device
PI_BAD_I2C_BUS : -74, // bad I2C bus
PI_BAD_I2C_ADDR : -75, // bad I2C address
PI_BAD_SPI_CHANNEL : -76, // bad SPI channel
PI_BAD_FLAGS : -77, // bad i2c/spi/ser open flags
PI_BAD_SPI_SPEED : -78, // bad SPI speed
PI_BAD_SER_DEVICE : -79, // bad serial device name
PI_BAD_SER_SPEED : -80, // bad serial baud rate
PI_BAD_PARAM : -81, // bad i2c/spi/ser parameter
PI_I2C_WRITE_FAILED : -82, // i2c write failed
PI_I2C_READ_FAILED : -83, // i2c read failed
PI_BAD_SPI_COUNT : -84, // bad SPI count
PI_SER_WRITE_FAILED : -85, // ser write failed
PI_SER_READ_FAILED : -86, // ser read failed
PI_SER_READ_NO_DATA : -87, // ser read no data available
PI_UNKNOWN_COMMAND : -88, // unknown command
PI_SPI_XFER_FAILED : -89, // spi xfer/read/write failed
PI_BAD_POINTER : -90, // bad (NULL) pointer
PI_NO_AUX_SPI : -91, // no auxiliary SPI on Pi A or B
PI_NOT_PWM_GPIO : -92, // GPIO is not in use for PWM
PI_NOT_SERVO_GPIO : -93, // GPIO is not in use for servo pulses
PI_NOT_HCLK_GPIO : -94, // GPIO has no hardware clock
PI_NOT_HPWM_GPIO : -95, // GPIO has no hardware PWM
PI_BAD_HPWM_FREQ : -96, // hardware PWM frequency not 1-125M
PI_BAD_HPWM_DUTY : -97, // hardware PWM dutycycle not 0-1M
PI_BAD_HCLK_FREQ : -98, // hardware clock frequency not 4689-250M
PI_BAD_HCLK_PASS : -99, // need password to use hardware clock 1
PI_HPWM_ILLEGAL : -100, // illegal, PWM in use for main clock
PI_BAD_DATABITS : -101, // serial data bits not 1-32
PI_BAD_STOPBITS : -102, // serial (half) stop bits not 2-8
PI_MSG_TOOBIG : -103, // socket/pipe message too big
PI_BAD_MALLOC_MODE : -104, // bad memory allocation mode
PI_TOO_MANY_SEGS : -105, // too many I2C transaction segments
PI_BAD_I2C_SEG : -106, // an I2C transaction segment failed
PI_BAD_SMBUS_CMD : -107, // SMBus command not supported by driver
PI_NOT_I2C_GPIO : -108, // no bit bang I2C in progress on GPIO
PI_BAD_I2C_WLEN : -109, // bad I2C write length
PI_BAD_I2C_RLEN : -110, // bad I2C read length
PI_BAD_I2C_CMD : -111, // bad I2C command
PI_BAD_I2C_BAUD : -112, // bad I2C baud rate, not 50-500k
PI_CHAIN_LOOP_CNT : -113, // bad chain loop count
PI_BAD_CHAIN_LOOP : -114, // empty chain loop
PI_CHAIN_COUNTER : -115, // too many chain counters
PI_BAD_CHAIN_CMD : -116, // bad chain command
PI_BAD_CHAIN_DELAY : -117, // bad chain delay micros
PI_CHAIN_NESTING : -118, // chain counters nested too deeply
PI_CHAIN_TOO_BIG : -119, // chain is too long
PI_DEPRECATED : -120, // deprecated function removed
PI_BAD_SER_INVERT : -121, // bit bang serial invert not 0 or 1
PI_BAD_EDGE : -122, // bad ISR edge value, not 0-2
PI_BAD_ISR_INIT : -123, // bad ISR initialisation
PI_BAD_FOREVER : -124, // loop forever must be last command
PI_BAD_FILTER : -125, // bad filter parameter
PI_BAD_PAD : -126, // bad pad number
PI_BAD_STRENGTH : -127, // bad pad drive strength
PI_FIL_OPEN_FAILED : -128, // file open failed
PI_BAD_FILE_MODE : -129, // bad file mode
PI_BAD_FILE_FLAG : -130, // bad file flag
PI_BAD_FILE_READ : -131, // bad file read
PI_BAD_FILE_WRITE : -132, // bad file write
PI_FILE_NOT_ROPEN : -133, // file not open for read
PI_FILE_NOT_WOPEN : -134, // file not open for write
PI_BAD_FILE_SEEK : -135, // bad file seek
PI_NO_FILE_MATCH : -136, // no files match pattern
PI_NO_FILE_ACCESS : -137, // no permission to access file
PI_FILE_IS_A_DIR : -138, // file is a directory
PI_BAD_SHELL_STATUS : -139, // bad shell return status
PI_BAD_SCRIPT_NAME : -140, // bad script name
PI_BAD_SPI_BAUD : -141, // bad SPI baud rate, not 50-500k
PI_NOT_SPI_GPIO : -142, // no bit bang SPI in progress on GPIO
PI_BAD_EVENT_ID : -143, // bad event id
PI_PIGIF_ERR_0 : -2000,
PI_PIGIF_ERR_99 : -2099,
PI_CUSTOM_ERR_0 : -3000,
PI_CUSTOM_ERR_999 : -3999
});

View File

@@ -0,0 +1,440 @@
/* eslint-env node */
const def = require('./definitions.js');
const net = require('net');
const assert = require('assert');
const reverse_string_and_clean = require('./utils.js').reverse_string_and_clean;
const _pi_gpio_command = require('./utils.js')._pi_gpio_command;
const _socklock = require('./utils.js')._socklock;
const _callback = require ('./_callback.js')._callback;
const _callback_thread = require ('./_callback.js')._callback_thread;
/** @class */
function pigpio() {
"use strict";
}
pigpio.prototype = {
// GPIO levels
OFF: 0,
LOW: 0,
CLEAR: 0,
ON: 1,
HIGH: 1,
SET: 1,
TIMEOUT: 2,
// GPIO edges
RISING_EDGE: 0,
FALLING_EDGE: 1,
EITHER_EDGE: 2,
// GPIO modes
INPUT: 0,
OUTPUT: 1,
ALT0: 4,
ALT1: 5,
ALT2: 6,
ALT3: 7,
ALT4: 3,
ALT5: 2,
// GPIO Pull Up Down
PUD_OFF: 0,
PUD_DOWN: 1,
PUD_UP: 2
};
/**
*
* Connects to the pigpio daemon.
*
* This method has to be called before it's possible to do anything with
* the GPIO pins.
*
* The callback will be called when the connection has been established or
* if an error occurs.
*
* @param {string} [host] - The host to connect to.
* @param {number} [port] - The port on the host to connect to.
* @param {Object} [cb] - Callback function.
*/
pigpio.prototype.pi = function(host, port, cb) {
"use strict";
const that = this;
if (host === undefined) {
host = process.env.PIGPIO_ADDR || 'localhost';
}
if (port === undefined) {
port = process.env.PIGPIO_PORT || '8888';
}
this._notify = null;
this.sl = new _socklock(host, port);
this.sl.s = net.connect({host, port});
this.sl.s.on('connect', () => {
// Disable the Nagle algoritm
that.sl.s.setNoDelay(true);
that._notify = new _callback_thread(that.sl,host, port, (e)=>{
cb(e);
});
});
this.sl.s.on("data", (data) => {
const command = parseInt(data.toString('hex').substr(0,2),16);
if (that.sl._next[command] !== undefined) {
that.sl._next[command](undefined, reverse_string_and_clean(data.toString('hex')));
}
that.sl._releaseLock();
});
this.sl.s.on('error', (e) => {
cb(e);
});
};
/**
* Half-closes the connection. We might still get some data from the server.
*/
pigpio.prototype.close = function() {
"use strict";
this.sl.s.end();
};
/**
*
* Starts (500-2500) or stops (0) servo pulses on the given gpio pin.
*
* The selected pulsewidth will continue to be transmitted until
* changed by a subsequent call to set_servo_pulsewidth.
*
* The pulsewidths supported by servos varies and should probably
* be determined by experiment. A value of 1500 should always be
* safe and represents the mid-point of rotation.
*
* You can DAMAGE a servo if you command it to move beyond its
* limits.
*
* @example
* gpio.setServoPulsewidth(17, 0) # off
* gpio.setServoPulsewidth(17, 1000) # safe anti-clockwise
* gpio.setServoPulsewidth(17, 1500) # centre
* gpio.setServoPulsewidth(17, 2000) # safe clockwise
*
* @param {number} userGpio - The number of the gpio to address. 0-31.
* @param {number} pulseWidth - The servo pulsewidth to generate
* 0 (off),
* 500 (most anti-clockwise) - 2500 (most clockwise).
*/
pigpio.prototype.setServoPulsewidth = function(userGpio, pulseWidth) {
"use strict";
assert_gpio_pin_in_range(userGpio,0,31);
assert(pulseWidth>=0 && pulseWidth <=2500, "pulsWidth must be in the range 0-2500");
_pi_gpio_command(this.sl,def.PI_CMD_SERVO, userGpio, pulseWidth);
};
/**
* Returns the GPIO level.
*
* @param {number} userGpio - The number of the gpio to address. 0-31.
* @param {callback} cb - The function to be called with the result.
*/
pigpio.prototype.read = function (userGpio, cb) {
"use strict";
assert_gpio_pin_in_range(userGpio,0,31);
_pi_gpio_command(this.sl,def.PI_CMD_READ, userGpio, 0, cb, true);
};
/**
* Returns the GPIO level.
*
* @param {number} userGpio - The number of the gpio to address. 0-31.
* @param {number} level - The output level 0 or 1.
* @param {callback} cb - The function to be called with the result.
*/
pigpio.prototype.write = function (userGpio, level, cb) {
"use strict";
assert_gpio_pin_in_range(userGpio,0,31);
assert(level===0 || level ===1, "level must be 0 or 1.");
_pi_gpio_command(this.sl,def.PI_CMD_WRITE, userGpio, level, cb, false);
};
/**
* Starts (non-zero dutycycle) or stops (0) PWM pulses on the gpio.
*
* @example
* pi.set_PWM_dutycycle(4, 0) # PWM off
* pi.set_PWM_dutycycle(4, 64) # PWM 1/4 on
* pi.set_PWM_dutycycle(4, 128) # PWM 1/2 on
* pi.set_PWM_dutycycle(4, 192) # PWM 3/4 on
* pi.set_PWM_dutycycle(4, 255) # PWM full on
*
* @param {number} userGpio - The number of the gpio to address (0-31).
* @param {number} dutycycle - The pwm dutycycle to use:
* 0 (off),
* 255 (full on).
*/
pigpio.prototype.set_PWM_dutycycle = function(userGpio, dutycycle) {
"use strict";
assert_gpio_pin_in_range(userGpio,0,31);
assert(dutycycle>=0 && dutycycle <=255, "dutycycle must be in the range 0-255");
_pi_gpio_command(this.sl,def.PI_CMD_PWM, userGpio, dutycycle, undefined, true);
};
/**
* Returns the PWM dutycycle being used on the GPIO.
*
* For normal PWM the dutycycle will be out of the defined range
* for the GPIO (see [*get_PWM_range*]).
* If a hardware clock is active on the GPIO the reported
* dutycycle will be 500000 (500k) out of 1000000 (1M).
* If hardware PWM is active on the GPIO the reported dutycycle
* will be out of a 1000000 (1M).
*
* @param {number} userGpio - The number of the gpio to address (0-31).
* @param {callback} cb - Function that the value will be passed back to in form function(err, data).
*/
pigpio.prototype.get_PWM_dutycycle = function(userGpio, cb) {
"use strict";
assert_gpio_pin_in_range(userGpio,0,31);
_pi_gpio_command(this.sl,def.PI_CMD_GDC, userGpio, 0, cb, true);
};
/**
* Sets the range of PWM values to be used on the GPIO.
*
* @param {number} userGpio - The number of the gpio to address (0-31).
* @param {number} range - A number in the range 25-40000.
*
* @example
* pi.set_PWM_range(9, 100) // now 25 1/4, 50 1/2, 75 3/4 on
* pi.set_PWM_range(9, 500) // now 125 1/4, 250 1/2, 375 3/4 on
* pi.set_PWM_range(9, 3000) // now 750 1/4, 1500 1/2, 2250 3/4 on
*/
pigpio.prototype.set_PWM_range = function (userGpio, range) {
"use strict";
assert_gpio_pin_in_range(userGpio,0,31);
assert(range>=25 && range <=40000, "range must be in the range 25-40000.");
_pi_gpio_command(this.sl,def.PI_CMD_PRS, userGpio, range, undefined, true);
};
/**
* Returns the range of PWM values being used on the GPIO.
* If a hardware clock or hardware PWM is active on the GPIO the reported range will be 1000000 (1M).
*
* @param {number} userGpio - The number of the gpio to address (0-31).
* @param {callback} cb - Function that the value will be passed back to in form function(err, data).
*/
pigpio.prototype.get_PWM_range = function(userGpio, cb) {
"use strict";
assert_gpio_pin_in_range(userGpio,0,31);
_pi_gpio_command(this.sl,def.PI_CMD_PRG, userGpio, 0, cb, true);
};
/**
* Returns the real (underlying) range of PWM values being used on the GPIO.
*
* If a hardware clock is active on the GPIO the reported real range will be 1000000 (1M).
* If hardware PWM is active on the GPIO the reported real range
* will be approximately 250M divided by the set PWM frequency.
*
* @param {number} userGpio - The number of the gpio to address (0-31).
* @param {callback} cb - Function that the value will be passed back to in form function(err, data).
*/
pigpio.prototype.get_PWM_real_range = function(userGpio, cb) {
"use strict";
assert_gpio_pin_in_range(userGpio,0,31);
_pi_gpio_command(this.sl,def.PI_CMD_PRRG, userGpio, 0, cb, true);
};
/**
* Sets the frequency (in Hz) of the PWM to be used on the GPIO.
*
* If PWM is currently active on the GPIO it will be switched
* off and then back on at the new frequency.
* Each GPIO can be independently set to one of 18 different PWM frequencies.
* The selectable frequencies depend upon the sample rate which
* may be 1, 2, 4, 5, 8, or 10 microseconds (default 5).
* The sample rate is set when the pigpio daemon is started.
*
* The frequencies for each sample rate are:
* hertz
* 1: 40000 20000 10000 8000 5000 4000 2500 2000 1600
* 1250 1000 800 500 400 250 200 100 50
* 2: 20000 10000 5000 4000 2500 2000 1250 1000 800
* 625 500 400 250 200 125 100 50 25
* 4: 10000 5000 2500 2000 1250 1000 625 500 400
* 313 250 200 125 100 63 50 25 13
* sample
* rate
* (us) 5: 8000 4000 2000 1600 1000 800 500 400 320
* 250 200 160 100 80 50 40 20 10
* 8: 5000 2500 1250 1000 625 500 313 250 200
* 156 125 100 63 50 31 25 13 6
* 10: 4000 2000 1000 800 500 400 250 200 160
* 125 100 80 50 40 25 20 10 5.
*
* @param {number} userGpio - The number of the gpio to address (0-31).
* @param {number} frequency - Frequency >=0 Hz.
*/
pigpio.prototype.set_PWM_frequency = function (userGpio, frequency) {
"use strict";
assert_gpio_pin_in_range(userGpio,0,31);
assert(frequency>=0, "frequency must be greater than or equal to 0");
_pi_gpio_command(this.sl,def.PI_CMD_PFS, userGpio, frequency);
};
/**
* Returns the frequency of PWM being used on the GPIO.
*
* @param {number} userGpio - The number of the gpio to address (0-31).
* @param {callback} cb - Function that the value will be passed back to in form function(err, data).
*/
pigpio.prototype.get_PWM_frequency = function(userGpio, cb) {
"use strict";
assert_gpio_pin_in_range(userGpio,0,31);
_pi_gpio_command(this.sl,def.PI_CMD_PFG, userGpio, 0, cb, true);
};
/**
* Calls a user supplied function (a callback) whenever the specified GPIO edge is detected.
*
* The user supplied callback receives three parameters, the GPIO, the level, and the tick.
*
* If a user callback is not specified a default tally callback is
* provided which simply counts edges. The count may be retrieved
* by calling the tally function. The count may be reset to zero
* by calling the reset_tally function.
*
* The callback may be cancelled by calling the cancel function.
*
* A GPIO may have multiple callbacks (although I can't think of
* a reason to do so).
*
* @param {number} userGpio - The number of the gpio to address (0-31).
* @param {number} edge - Indicate the edge to detect.
* @param {callback} cb - Callback to be run.
*/
pigpio.prototype.callback = function (userGpio, edge, cb) {
"use strict";
assert_gpio_pin_in_range(userGpio,0,31);
return new _callback (this._notify, userGpio, edge, cb);
};
/**
*
* Returns the Pi's hardware revision number.
*
* The hardware revision is the last few characters on the Revision line of /proc/cpuinfo.
* The revision number can be used to determine the assignment of GPIO to pins (see [*gpio*]).
* There are at least three types of board.
* * Type 1 boards have hardware revision numbers of 2 and 3.
* * Type 2 boards have hardware revision numbers of 4, 5, 6, and 15.
* * Type 3 boards have hardware revision numbers of 16 or greater.
* * If the hardware revision can not be found or is not a valid hexadecimal number the function returns 0.
*
* @param {callback} cb - Callback that will receive the result in form of function (err, data).
*/
pigpio.prototype.getHardwareRevision = function(cb) {
"use strict";
_pi_gpio_command(this.sl,def.PI_CMD_HWVER, 0, 0, cb, true);
};
/**
* Sets the GPIO mode.
*
* @param {number} gpio - Port 0-53.
* @param {string} mode - Must be either INPUT, OUTPUT, ALT0, ALT1, ALT2, ALT3, ALT4 or ALT5.
*/
pigpio.prototype.set_mode = function (gpio, mode) {
"use strict";
assert_gpio_pin_in_range(gpio,0,53);
assert([this.INPUT, this.OUTPUT, this.ALT0, this.ALT1, this.ALT2, this.ALT3, this.ALT4, this.ALT5].includes(mode), "Mode must be INPUT, OUTPUT, ALT0, ALT1, ALT2, ALT3, ALT4, ALT5");
_pi_gpio_command(this.sl,def.PI_CMD_MODES, gpio, mode);
};
/**
* Returns the GPIO mode.
*
* @param {number} gpio - Port 0-53.
* @param {callback} callback - Function to be run when the data has been received.
*/
pigpio.prototype.get_mode = function (gpio, callback) {
"use strict";
assert_gpio_pin_in_range(gpio,0,53);
_pi_gpio_command(this.sl,def.PI_CMD_MODEG, gpio, 0, callback, true);
}
/**
* Sets or clears the internal GPIO pull-up/down resistor.
*
* @param {number} gpio - Port 0-53.
* @param {string} pud - Must be either PUD_UP, PUD_DOWN, PUD_OFF.
*/
pigpio.prototype.set_pull_up_down = function (gpio, pud) {
"use strict";
assert_gpio_pin_in_range(gpio,0,53);
assert([this.PUD_DOWN, this.PUD_OFF, this.PUD_UP].includes(pud), "pud must be PUD_UP, PUD_DOWN, PUD_OFF");
_pi_gpio_command(this.sl,def.PI_CMD_PUD, gpio, pud);
};
/**
* Sets a glitch filter on a GPIO.
*
* Level changes on the GPIO are not reported unless the level
* has been stable for at least [*steady*] microseconds. The
* level is then reported. Level changes of less than [*steady*]
* microseconds are ignored.
*
* @param {number} gpio - Port 0-31.
* @param {number} steady - Number of setmicroseconds after detection before a change is confirmed.
*/
pigpio.prototype.set_glitch_filter = function (gpio, steady) {
"use strict";
assert_gpio_pin_in_range(gpio,0,31);
assert(steady>=0 && steady<=300000, "steady must be in the range 0 - 30000");
_pi_gpio_command(this.sl,def.PI_CMD_FG, gpio, steady);
};
/**
* Calls a user supplied function (a callback) whenever the
* specified GPIO edge is detected.
*
* If a user callback is not specified a default tally callback is
* provided which simply counts edges. The count may be retrieved
* by calling the tally function. The count may be reset to zero
* by calling the reset_tally function.
*
* The callback may be cancelled by calling the cancel function.
*
* A GPIO may have multiple callbacks (although I can't think of
* a reason to do so).
*
* @param {number} userGpio - Port 0-31.
* @param {number} edge - Must be EITHER_EDGE, RISING_EDGE (default), or FALLING_EDGE.
* @param {callback} func - User supplied callback function.
* The user supplied callback receives three parameters, the GPIO, the level, and the tick.
*/
pigpio.prototype.callback = function (userGpio, edge, func) {
"use strict";
assert_gpio_pin_in_range(userGpio,0,31);
if (edge === undefined || edge === null) {
edge = this.RISING_EDGE;
}
assert (edge === this.EITHER_EDGE || edge === this.RISING_EDGE || edge === this.FALLING_EDGE);
return new _callback(this._notify, userGpio, edge, func)
}
function assert_gpio_pin_in_range (gpio, low , high) {
"use strict";
assert(gpio >= low && gpio <= high, 'userGpio must be in the range ' + low + '-' + high + '31');
}
module.exports = pigpio;

View File

@@ -0,0 +1,89 @@
const assert = require('assert');
exports.reverse_string_and_clean = function (str) {
var result='';
var i = str.length-1;
while (i>str.length-9) {
result +=str [i-1] + str[i] ;
i -=2;
}
return parseInt(result,'16');
};
exports.reverse_string = function (str) {
var result='';
var i = str.length-1;
while (i>0) {
result +=str [i-1] + str[i] ;
i -=2;
}
return parseInt(result,'16');
};
const _LOCKS = [];
/**
* A class to store socket and lock.
* @private
*/
class _socklock {
constructor(host, port) {
this.s = null;
this.host = host;
this.port = port;
this._next = [];
}
/* eslint: no-unmodified-loop-condition */
_acquireLock() {
"use strict";
let timeout = false;
setTimeout(() => {
timeout = true
}, 500);
/* eslint-disable no-unmodified-loop-condition */
while (!timeout && _LOCKS[this.host + ':' + this.port] !== undefined) {
if (_LOCKS[this.host + ':' + this.port] === undefined) {
_LOCKS[this.host + ':' + this.port] = 'Locked';
} else {
throw new Error('Can not acquire Lock');
}
}
/* eslint-disable no-unmodified-loop-condition */
}
_releaseLock() {
"use strict";
if (_LOCKS[this.host + ':' + this.port] !== undefined) {
_LOCKS[this.host + ':' + this.port] = undefined;
}
}
}
exports._socklock = _socklock;
exports._pi_gpio_command = function(socketlock, command, parameter1, parameter2, next, wait_for_response) {
"use strict";
assert(command !== undefined, "No command specified");
// console.log("Receviced _pi_gpio_command "+command+" | "+parameter1+" | "+parameter2)
const cmd = Buffer.alloc(16); // Crée un tampon de 16 octets
cmd.writeUInt32LE(command, 0);
cmd.writeUInt32LE(parameter1, 4);
cmd.writeUInt32LE(parameter2, 8);
cmd.writeUInt32LE(0, 12);
socketlock._acquireLock();
if (next !== undefined) {
socketlock._next[command] = next;
}
if(!socketlock.s.write(cmd)) {
next(new Error("Error Sending Command to Pi: "+command));
}
if(!wait_for_response) {
socketlock._releaseLock();
}
};

View File

@@ -1,9 +1,8 @@
{
"name": "node-red-node-pi-gpiod",
"version": "0.4.0",
"version": "0.5.0",
"description": "A node-red node for PiGPIOd",
"dependencies" : {
"js-pigpio": "*"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
@@ -18,7 +17,7 @@
],
"author": {
"name": "Dave Conway-Jones",
"email": "ceejay@vnet.ibm.com",
"email": "dceejay@gmail.com",
"url": "http://nodered.org"
},
"license": "Apache-2.0",

View File

@@ -1,7 +1,7 @@
module.exports = function(RED) {
"use strict";
var Pigpio = require('js-pigpio');
var Pigpio = require('./js-pigpio/index.js');
var bcm2pin = {
"2":"3", "3":"5", "4":"7", "14":"8", "15":"10", "17":"11", "18":"12", "27":"13", "22":"15",
@@ -50,12 +50,13 @@ module.exports = function(RED) {
node.status({fill:"green",shape:"dot",text:level});
});
if (node.read) {
setTimeout(function() {
var loop = setInterval(function() {
PiGPIO.read(node.pin, function(err, level) {
node.send({ topic:"pi/"+node.pio, payload:Number(level), host:node.host });
node.status({fill:"green",shape:"dot",text:level});
clearInterval(loop)
});
}, 20);
}, 5);
}
}
});