From eaccf3fd48837348c5278b7c96cb20248fbd53cc Mon Sep 17 00:00:00 2001 From: btsimonh Date: Fri, 27 Jan 2023 08:02:27 +0000 Subject: [PATCH 1/9] Add more i2c functions. --- pigpio-client.js | 94 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 2 deletions(-) diff --git a/pigpio-client.js b/pigpio-client.js index 22c49fa..c91f439 100644 --- a/pigpio-client.js +++ b/pigpio-client.js @@ -14,7 +14,11 @@ const ERR = SIF.PigpioErrors const { BR1, BR2, TICK, HWVER, PIGPV, PUD, MODES, MODEG, READ, WRITE, PWM, WVCLR, WVCRE, WVBSY, WVAG, WVCHA, NOIB, NB, NP, NC, SLRO, SLR, SLRC, SLRI, WVTXM, WVTAT, WVHLT, WVDEL, WVAS, HP, HC, GDC, PFS, FG, SERVO, GPW, TRIG, -I2CO, I2CC, I2CRD, I2CWD, BSCX, EVM +I2CO, I2CC, I2CRD, I2CWD, +I2CWQ, I2CRS, I2CWS, I2CRB, I2CWB, I2CRW, I2CWW, I2CRK, I2CWK, I2CRI, I2CWI, I2CPC, I2CPK, + +BSCX, EVM, +PROC, PROCD, PROCR, PROCS, PROCP, PROCU } = SIF.Commands // These command types can not fail, ie, always return p3/res as positive integer @@ -506,6 +510,9 @@ exports.pigpio = function (pi) { that.request = request + // export his so that we can extend externally more easily. + that.Commands = SIF.Commands; + that.connect = function() { if (commandSocket.destroy) { log('Remove all listeners and destroy command socket.') @@ -631,24 +638,107 @@ exports.pigpio = function (pi) { }) } + + // general note about returns with data. + // if using await fn(), you will get an array back [count, d0, d1, d2 ...] + // if using fn(callback), you will get (err, count, d0, d1, d2 ...) + that.i2cOpen = function (bus, device, callback) { let flags = new Uint8Array(4); // inits to zero return request(I2CO, bus, device, 4, callback, flags) } + // open with specified flags + that.i2cOpenF = function (bus, device, flags, callback) { + flags = flags || 0; + let flagsarr = [flags & 0xff, (flags >> 8)&0xff, (flags >> 16)&0xff, (flags >> 24)&0xff ]; + let buffer = Buffer.from(flagsarr); + return request(I2CO, bus, device, buffer.length, callback, buffer) + } + that.i2cClose = function (handle, callback) { return request(I2CC, handle, 0, 0, callback) } + // await: [count, d0, d1, d2 ...] callback:(err, count, d0, d1, d2 ...) that.i2cReadDevice = function (handle, count, callback) { return request(I2CRD, handle, count, 0, callback) } that.i2cWriteDevice = function (handle, data, callback) { let buffer = Buffer.from(data); - return request(I2CWD, handle, 0, data.length, callback, buffer) + return request(I2CWD, handle, 0, buffer.length, callback, buffer) + } + + that.i2cReadByteData = function (handle, reg, callback) { + return request(I2CRB, handle, reg, 0, callback) + } + + that.i2cWriteByteData = function (handle, reg, byte, callback) { + let buffer = Buffer.from([byte, 0, 0, 0]); + return request(I2CWB, handle, reg, buffer.length, callback, buffer) + } + + that.i2cReadByte = function (handle, callback) { + return request(I2CRS, handle, 0, 0, callback) + } + + that.i2cWriteByte = function (handle, byte, callback) { + return request(I2CWS, handle, byte, 0, callback) + } + + that.i2cWriteQuick = function (handle, bit, callback) { + return request(I2CWQ, handle, bit, 0, callback) + } + + that.i2cReadWordData = function (handle, reg, callback) { + return request(I2CRW, handle, reg, 0, callback) + } + + that.i2cWriteWordData = function (handle, reg, word, callback) { + let wordarr = [word & 0xff, (word >> 8)&0xff, 0,0 ]; + let buffer = Buffer.from(wordarr); + return request(I2CWW, handle, reg, buffer.length, callback, buffer); + } + + // await: [count, d0, d1, d2 ...] callback:(err, count, d0, d1, d2 ...) + that.i2cReadBlockData = function (handle, reg, callback) { + return request(I2CRK, handle, reg, 0, callback); } + // 1-32 bytes + that.i2cWriteBlockData = function (handle, reg, data, callback) { + let buffer = Buffer.from(data); + return request(I2CWK, handle, reg, buffer.length, callback, buffer); + } + + // read a block from reg with increment + // await: [count, d0, d1, d2 ...] callback:(err, count, d0, d1, d2 ...) + that.i2cReadI2cBlockData = function (handle, reg, len, callback) { + let lenarr = [len & 0xff, 0,0,0 ]; + let buffer = Buffer.from(lenarr); + return request(I2CRI, handle, reg, buffer.length, callback, buffer); + } + + that.i2cWriteI2cBlockData = function (handle, reg, data, callback) { + let buffer = Buffer.from(data); + return request(I2CWI, handle, reg, buffer.length, callback, buffer); + } + + // returns a word response. + that.i2cProcessCall = function (handle, reg, word, callback) { + let wordarr = [word & 0xff, (word >> 8)&0xff, 0, 0]; + let buffer = Buffer.from(wordarr); + return request(I2CPC, handle, reg, buffer.length, callback, buffer); + } + + // writes 1-32 bytes of data, returns count, and buffer with data. + // await: [count, d0, d1, d2 ...] callback:(err, count, d0, d1, d2 ...) + that.i2cBlockProcessCall = function (handle, reg, data, callback) { + let buffer = Buffer.from(data); + return request(I2CPK, handle, reg, buffer.length, callback, buffer); + } + that.bscI2C = function (address, data, callback) { let control if (address > 0 && address < 128) { From b10e517fe8efb04c5bab4ebeacab761e4c37b0f0 Mon Sep 17 00:00:00 2001 From: btsimonh Date: Fri, 27 Jan 2023 08:53:09 +0000 Subject: [PATCH 2/9] Add i2c example - driving PCA9685 for servos. --- examples/i2cPCA9685Servos.js | 347 +++++++++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 examples/i2cPCA9685Servos.js diff --git a/examples/i2cPCA9685Servos.js b/examples/i2cPCA9685Servos.js new file mode 100644 index 0000000..b140aba --- /dev/null +++ b/examples/i2cPCA9685Servos.js @@ -0,0 +1,347 @@ +// npm run-script usage +let host = '192.168.1.185' || process.env.npm_package_config_host; +const pigpio = require('../pigpio-client').pigpio({host: host}); + +const ready = new Promise((resolve, reject) => { + pigpio.once('connected', resolve); + pigpio.once('error', reject); +}); + +function wait(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +ready.then(async (info) => { + // display information on pigpio and connection status + console.log(JSON.stringify(info,null,2)); + addPCA9685Servos(pigpio); + + let servos = await pigpio.PCA9685Servos(); + + // dump areas of the device that we can read + await servos.dumpDevice(0, 70); + await servos.dumpDevice(250, 6); + + // wiggle the second servo + + + let s = { + min: 0.0, + max: 1.0, + index:1 + }; + let servo_width = s.min; + + let loops = 0; + let interval = setInterval(async ()=>{ + loops++; + if (loops > 3){ + console.log('servotest ending'); + clearInterval(interval); + // we should see the last values we set + await servos.dumpDevice(0, 70); + await servos.dumpDevice(250, 6); + + await servos.clearServos(); // stop all outputs + await servos.close(); // stop all outputs + console.log('servotest done'); + pigpio.end(); + return; + } + + if (servo_width === s.min){ + servo_width = s.max; + } else { + servo_width = s.min; + } + + //await servos.set_servo(servo_defn.camera, servo_width); + await servos.set_servo(s.index, servo_width); + + }, 1000); + +}); + + +function addPCA9685Servos(pigpio_instance){ + let pigpio = pigpio_instance; + pigpio_instance.PCA9685Servos = async function(opts) { + const DEFAULT_CYCLE_TIME_US = 1000000/50 // default to 50Hz -> 20,000uS + const DEFAULT_STEP_TIME_US = 5 // gives 400 steps for typical servo range + const DEFAULT_SERVO_MIN_US = 500 // Be aware that many cheap servos get very annoyed + const DEFAULT_SERVO_MAX_US = 2500// by getting pushed too far. Use the min/max + //const DEFAULT_SERVO_MIN_US = 500 // Be aware that many cheap servos get very annoyed + //const DEFAULT_SERVO_MAX_US = 2500// by getting pushed too far. Use the min/max + + const MAX_SERVOS = 16; + const I2C_BUS = 1; + const DEFAULT_PCA_ADDR = 0x40; + + const MODE1 =0x00 //Mode register 1 + const MODE2 =0x01 //Mode register 2 + const SUBADR1 =0x02 //I2C-bus subaddress 1 + const SUBADR2 =0x03 //I2C-bus subaddress 2 + const SUBADR3 =0x04 //I2C-bus subaddress 3 + const ALLCALLADR =0x05 //LED All Call I2C-bus address + const LED0 =0x6 //LED0 start register + const LED0_ON_L =0x6 //LED0 output and brightness control byte 0 + const LED0_ON_H =0x7 //LED0 output and brightness control byte 1 + const LED0_OFF_L =0x8 //LED0 output and brightness control byte 2 + const LED0_OFF_H =0x9 //LED0 output and brightness control byte 3 + const LED_MULTIPLYER =4 // For the other 15 channels + const ALLLED_ON_L =0xFA //load all the LEDn_ON registers, byte 0 (turn 0-7 channels on) + const ALLLED_ON_H =0xFB //load all the LEDn_ON registers, byte 1 (turn 8-15 channels on) + const ALLLED_OFF_L =0xFC //load all the LEDn_OFF registers, byte 0 (turn 0-7 channels off) + const ALLLED_OFF_H =0xFD //load all the LEDn_OFF registers, byte 1 (turn 8-15 channels off) + const PRE_SCALE =0xFE //prescaler for output frequency + const CLOCK_FREQ =25000000.0 //25MHz default osc clock + const BUFFER_SIZE =0x08 //1 byte buffer + // MODE1 reg flags + const RESTART =0x80 + const EXTCLK =0x40 + const AI =0x20 + const SLEEP =0x10 + const NOTSLEEP =0x7F + const SUB1 =0x8 + const SUB2 =0x4 + const SUB3 =0x2 + const ALLCALL =0x1 + // MODE2 reg flags + const INVRT =0x10 + const OCH =0x8 + const OUTDRV =0x4 + //const OUTNE // doesn't matter here + + + opts = opts || {}; + let defaultopts = { + servo_max_us: DEFAULT_SERVO_MAX_US, + servo_min_us: DEFAULT_SERVO_MIN_US, + cycle_time_us: DEFAULT_CYCLE_TIME_US, + }; + + opts = Object.assign({}, opts, defaultopts); + + let PCA9685 = { + + pca: undefined, + servowidth: [], + servostartus: [], + + bus: I2C_BUS, + i2c_address: DEFAULT_PCA_ADDR, + + cycle_time_us: 0, + servo_max_us: DEFAULT_SERVO_MAX_US, + servo_min_us: DEFAULT_SERVO_MIN_US, + + waitforme: function(millisec) { + return new Promise(resolve => { + setTimeout(() => { resolve('') }, millisec); + }); + }, + + init: async function(){ + try { + + // connect to the PCA9685 via i2c, quit if that fails + // Consider having the i2c address an argument when starting the daemon? + this.pca = await pigpio.i2cOpen(this.bus, this.i2c_address); + + console.log('i2c handle: '+this.pca); + + // initialise the PCA; write config byte to reg 0 + // See PCA9685.pdf 7.3.1 + // exactly what is best here is a bit arguable. I see 0x20 or 0x21 or 0 used variously + await pigpio.i2cWriteByteData(this.pca, MODE1, AI | ALLCALL); + + // maybe we should set some flags in MODE2 as well? + // 0xC is used in at least one python based driver + await pigpio.i2cWriteByteData(this.pca, MODE2, /*OCH | */ OUTDRV); + // we have to wait for at least 500uS after setting the SLEEP flag to 0 + await this.waitforme(10); + this.servo_max_us = opts.servo_max_us; + this.servo_min_us = opts.servo_min_us; + this.cycle_time_us = this.calculateTimerSettings(opts.cycle_time_us); + this.init_servo_starts(); + await this.setPwmFreq(); + // make all servos unpowered at start. + await this.clearServos(); + + + } catch(e){ + console.error('i2c init error', e); + } + }, + + dumpDevice: async function(start, len){ + // device has 256 registers, read in 32 byte chunks + let deviceData = []; + console.log('dump '+start +' for '+len); + + for (let i = start; i < start+len; i+= 32){ + let l = (start+len) - i; + if (l > 32) l = 32; + let res = await pigpio.i2cReadI2cBlockData(this.pca, i, l); + console.log('bytes read: '+res[0]+' bytes:'+ res.toString()); + res.shift(); + deviceData.push(...res); + } + for (let i = 0; i < deviceData.length; i+= 16){ + let addr = '0'+i.toString(16); + addr = addr.slice(-2); + let str = addr+': '; + let l = deviceData.length - i; + if (l > 16) l = 16; + for (let j = 0; j < l; j++){ + let val = '0'+deviceData[i+j].toString(16); + val = val.slice(-2); + str += val+' '; + } + console.log(str); + } + }, + + close: async function(){ + if (this.pca !== undefined){ + await this.clearServos(); + await this.setSleep(); // stop the clock + await pigpio.i2cClose(this.pca); + this.pca = undefined; + } + }, + + init_servo_starts: function() { + let us_per_servo = this.cycle_time_us/MAX_SERVOS; + let curr_us = 10; + + /* set the servo start ticks to spread out the current draw */ + for (let servo = 0; servo < MAX_SERVOS; servo++) { + this.servowidth.push(0); + this.servostartus.push(0); + this.servostartus[servo] = curr_us; + if (this.servostartus[servo] + this.servo_max_us >= this.cycle_time_us){ + curr_us = us_per_servo/3; + this.servostartus[servo] = curr_us; + } + curr_us += us_per_servo; + } + }, + + calculateTimerSettings: function(cycle_time) { + let freq = 1000000 / cycle_time; + this.timer_prescale = (CLOCK_FREQ / 4096 / freq) - 1; + //console.log("Setting prescale value to: "+ timer_prescale); + //console.log("Actual frequency: "+ (CLOCK_FREQ / 4096.0) / (timer_prescale + 1)); + // adjust the global cycle time to reflect reality + let cycle_time_us = 1000000 * (this.timer_prescale +1)/ (CLOCK_FREQ / 4096.0); + console.log("cycle time: "+ cycle_time_us+"ms"); + console.log("servo_min_us " +this.servo_min_us+" servo_max_us "+this.servo_max_us+ + " travel "+(this.servo_max_us - this.servo_min_us)+"us"); + let steps = ((((this.servo_max_us - this.servo_min_us)/cycle_time_us)*4096)>>0); + console.log("steps full travel "+ ((((this.servo_max_us - this.servo_min_us)/cycle_time_us)*4096)>>0)); + console.log("servo resolution ~"+(((10000/steps)>>0)/100)+"%"); + return cycle_time_us; + }, + + setPwmFreq: async function (){ + let oldmode = await pigpio.i2cReadByteData(this.pca, MODE1); + let newmode = (oldmode & NOTSLEEP) | SLEEP; //sleep + await pigpio.i2cWriteByteData(this.pca, MODE1, newmode); // go to sleep + await pigpio.i2cWriteByteData(this.pca, PRE_SCALE, this.timer_prescale); + await pigpio.i2cWriteByteData(this.pca, MODE1, oldmode); + await this.waitforme(10); + await pigpio.i2cWriteByteData(this.pca, MODE1, oldmode | RESTART); + }, + + setSleep: async function(){ + try{ + let oldmode = await pigpio.i2cReadByteData(this.pca, MODE1); + let newmode = (oldmode & NOTSLEEP) | SLEEP; //sleep + await pigpio.i2cWriteByteData(this.pca, MODE1, newmode); // go to sleep + } catch(e){ + console.error(e); + } + }, + + // could be done with a single block read? + read_servo: async function (servo) { + // illustrate use of i2cReadWordData + let onw = await pigpio.i2cReadWordData(this.pca, LED0_ON_L + LED_MULTIPLYER * servo); + let offw = await pigpio.i2cReadWordData(this.pca, LED0_OFF_L + LED_MULTIPLYER * servo); + console.log({ onw, offw }); + + // illustrate use of i2cReadI2cBlockData + // note because await, we get an array back which starts with length + let b = await pigpio.i2cReadI2cBlockData(this.pca, LED0_ON_L + LED_MULTIPLYER * servo, 4); + let len = b[0]; + let on = b[1] | (b[2]<<8); + let off = b[3] | (b[4] << 8); + console.log({ on, off }); + + return {on, off}; + }, + + + set_servo: async function(servo, width) { + try { + if (width === -1){ + // illustrate use of i2cWriteWordData to set on and off separately. + await pigpio.i2cWriteWordData(this.pca, LED0_ON_L + LED_MULTIPLYER * servo, 0); + await pigpio.i2cWriteWordData(this.pca, LED0_OFF_L + LED_MULTIPLYER * servo, 0); + } else { + this.servowidth[servo] = width; + //console.log( `set servo[${servo}]=${width*100}`); + // set this servo to start at the servostart tick and stay on for width ticks + let range = (this.servo_max_us - this.servo_min_us); + let val = this.servowidth[servo] * range; + let dur = this.servo_min_us + val; + + let on_us = this.servostartus[servo]; + let off_us = on_us + dur; + + let on_value = ((on_us/this.cycle_time_us)*4096)>>0; + let off_value = ((off_us/this.cycle_time_us)*4096)>>0; + + //console.log(`rangeus ${range} valus ${val} durus ${dur} offval ${off_value}`); + if (off_value > 4095) off_value = 4095; + on_value = on_value >> 0; + off_value = off_value >> 0; + + let data = [on_value & 0xff,(on_value >>8) & 0xff, off_value & 0xff,(off_value >>8) & 0xff ]; + + // illustrate use of i2cWriteI2cBlockData to set all 4 regs at the same time. + await pigpio.i2cWriteI2cBlockData(this.pca, LED0_ON_L + LED_MULTIPLYER * servo, data); + + let res = await this.read_servo(servo); + let diff = (res.off - res.on)*this.cycle_time_us/4096; + let percent = (((((diff - this.servo_min_us) / range)*100)*10)>>0)/10; + console.log('read servo '+servo, res, ''+(diff>>0)+'us', percent+'%'); + } + + } catch (e){ + console.log('read servo exception', e); + } + }, + + clearServos: async function (){ + for (let i = 0; i < MAX_SERVOS; i++){ + await this.set_servo(i, -1); + } + }, + + allServos: async function (val){ + for (let i = 0; i < MAX_SERVOS; i++){ + await this.set_servo(i, val); + } + }, + }; + + + console.log(PCA9685); + + await PCA9685.init(); + + return PCA9685; + }; +} From 2e9aa5ef4ce8e6bbf0d397f56c9434baaefd1854 Mon Sep 17 00:00:00 2001 From: btsimonh Date: Fri, 27 Jan 2023 09:07:20 +0000 Subject: [PATCH 3/9] update readme for i2c functions. --- readme.md | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 38538b2..5cb5136 100644 --- a/readme.md +++ b/readme.md @@ -115,12 +115,17 @@ Note: Unless otherwise stated, all references to gpio pin numbers use **Broadcom **`pigpio.connect()`** Re-establishes communication with server after being disconnected. -**`pigpio.i2cOpen(bus, address, callback)`** Return a handle for communication +**`pigpio.i2cOpen(bus, address, flags?, callback)`** Return a handle for communication with a device attached to a bus on the I2C peripheral. `bus==0` uses (Broadcom) gpio 0 and 1, while `bus==1` use gpio 2 and 3 for SDA and SCL respectively. `address` takes values 1-127. +May be called as `pigpio.i2cOpen(bus, address, callback)` - flags will default to zero **`pigpio.i2cClose(handle, callback)`** Close the I2C device associated with handle. +general note about returns with data. +if using await fn(), you will get an array back [count, d0, d1, d2 ...] +if using fn(callback), you will get (err, count, d0, d1, d2 ...) + **`pigpio.i2cReadDevice(handle, count, callback)`** Read count bytes from the i2c device referred by handle. Returns tuple (error, count, data). `error` is 0 on success or an error code. `count` is the number of bytes read. `data` is a buffer. @@ -129,6 +134,40 @@ success or an error code. `count` is the number of bytes read. `data` is a buf referred by handle. `data` is a byte array or utf8 string. Returns 0 if OK, otherwise an error code. +**`pigpio.i2cReadByteData(handle, reg, callback)`** Read a byte from a reg + +**`pigpio.i2cWriteByteData(handle, reg, byte, callback)`** Write a byte to a reg + +**`pigpio.i2cReadByte = function (handle, callback)`** Read a byte from a device + +**`pigpio.i2cWriteByte(handle, byte, callback)`** Write a byte from a device + +**`pigpio.i2cWriteQuick(handle, bit, callback)`** Write a bit to a device + +**`pigpio.i2cReadWordData(handle, reg, callback)`** Read a 16 bit word from a reg + +**`pigpio.i2cWriteWordData(handle, reg, word, callback)`** Write a 16 bit word from a reg + +**`pigpio.i2cReadBlockData(handle, reg, callback)`** Read a block from a reg +await: [count, d0, d1, d2 ...] callback:(err, count, d0, d1, d2 ...) + +**`pigpio.i2cWriteBlockData(handle, reg, data, callback)`** Read a block to a reg +1-32 bytes as array, or anything which can be used by Buffer.from(var) + +**`pigpio.i2cReadI2cBlockData(handle, reg, len, callback)`** Read a block from reg with increment +1-32 bytes +await: [count, d0, d1, d2 ...] callback:(err, count, d0, d1, d2 ...) + +**`pigpio.i2cWriteI2cBlockData(handle, reg, data, callback)`** Write a block from reg with increment +1-32 bytes as array, or anything which can be used by Buffer.from(var) + +**`pigpio.i2cProcessCall = function (handle, reg, word, callback)`** Write a word (16 bit) +returns a word (16 bit) response. + +**`pigpio.i2cBlockProcessCall(handle, reg, data, callback)`** Write a block to a reg, +writes 1-32 bytes of data, returns data. +await: [count, d0, d1, d2 ...] callback:(err, count, d0, d1, d2 ...) + **`pigpio.bscI2C(address, data, callback)`** Transfer data to/from the BSC I2C slave peripheral using gpio 18 (SDA) and 19 (SCL). The data bytes (if any) are written to the BSC transmit FIFO and the bytes in the BSC receive FIFO are From c419ebe273a376a02b38cb0e60ee9158da54d541 Mon Sep 17 00:00:00 2001 From: btsimonh Date: Fri, 27 Jan 2023 09:08:02 +0000 Subject: [PATCH 4/9] update i2cOpen to accept flags, but in a backward compatible way. --- pigpio-client.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pigpio-client.js b/pigpio-client.js index c91f439..30e9646 100644 --- a/pigpio-client.js +++ b/pigpio-client.js @@ -643,13 +643,11 @@ exports.pigpio = function (pi) { // if using await fn(), you will get an array back [count, d0, d1, d2 ...] // if using fn(callback), you will get (err, count, d0, d1, d2 ...) - that.i2cOpen = function (bus, device, callback) { - let flags = new Uint8Array(4); // inits to zero - return request(I2CO, bus, device, 4, callback, flags) - } - - // open with specified flags - that.i2cOpenF = function (bus, device, flags, callback) { + that.i2cOpen = function (bus, device, flags, callback) { + if (typeof flags === 'function'){ + callback = flags; + flags = 0; // inits to zero + } flags = flags || 0; let flagsarr = [flags & 0xff, (flags >> 8)&0xff, (flags >> 16)&0xff, (flags >> 24)&0xff ]; let buffer = Buffer.from(flagsarr); From cb529c8e617c9d077f02c324d65788922ee49cef Mon Sep 17 00:00:00 2001 From: btsimonh Date: Thu, 16 Feb 2023 08:33:05 +0000 Subject: [PATCH 5/9] update i2c block functions to return sized arrays without leading size byte. Add BE functions. Add helper - so you can, e.g. let i2c = await pigpio.isc(bus, addr); let v = await i2c.readByteData(reg); --- pigpio-client.js | 273 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 255 insertions(+), 18 deletions(-) diff --git a/pigpio-client.js b/pigpio-client.js index 30e9646..5473c0f 100644 --- a/pigpio-client.js +++ b/pigpio-client.js @@ -639,10 +639,12 @@ exports.pigpio = function (pi) { } - // general note about returns with data. - // if using await fn(), you will get an array back [count, d0, d1, d2 ...] - // if using fn(callback), you will get (err, count, d0, d1, d2 ...) - + ////////////////////////////////////////////////////////////////////////////////////// + // i2c master functions + // general note about returns with buffer data. + // if using await fn(), you will get an array back [d0, d1, d2 ...] + // if using fn(callback), you will get (err, [d0, d1, d2 ...]) + that.i2cOpen = function (bus, device, flags, callback) { if (typeof flags === 'function'){ callback = flags; @@ -658,9 +660,9 @@ exports.pigpio = function (pi) { return request(I2CC, handle, 0, 0, callback) } - // await: [count, d0, d1, d2 ...] callback:(err, count, d0, d1, d2 ...) + // await: [d0, d1, d2 ...] callback:(err, [d0, d1, d2 ...]) that.i2cReadDevice = function (handle, count, callback) { - return request(I2CRD, handle, count, 0, callback) + return this._i2cRequestProcessBlock(I2CRD, handle, count, 0, callback) } that.i2cWriteDevice = function (handle, data, callback) { @@ -673,6 +675,7 @@ exports.pigpio = function (pi) { } that.i2cWriteByteData = function (handle, reg, byte, callback) { + // pigpio expects 4 byte 'extra data' for byte and word. let buffer = Buffer.from([byte, 0, 0, 0]); return request(I2CWB, handle, reg, buffer.length, callback, buffer) } @@ -686,22 +689,101 @@ exports.pigpio = function (pi) { } that.i2cWriteQuick = function (handle, bit, callback) { - return request(I2CWQ, handle, bit, 0, callback) + return request(I2CWQ, handle, bit, 0, callback); } + // read a word from a little-endian device. that.i2cReadWordData = function (handle, reg, callback) { - return request(I2CRW, handle, reg, 0, callback) + return request(I2CRW, handle, reg, 0, callback); + } + that.i2cReadWordDataLE = that.i2cReadWordData; + + // make a request, but byte-swap the word response before returning. + // note that for readWordBE, len is zero and buffer undefined. + that._i2cRequestSwapWordResponse = function(funct, handle, reg, len, callback, buffer){ + let cb; + let promise; + if (callback){ + cb = (err, word)=>{ + word = word || 0; + word = ((word >> 8) & 0xff) | ((word & 0xff)<<8); + callback(err, word); + }; + } else { + promise = new Promise((resolve, reject) => { + cb = (error, ...args) => { + if (error) { + reject(error) + } else { + let word = args[0]; + word = word || 0; + word = ((word >> 8) & 0xff) | ((word & 0xff) << 8); + resolve(word); + } + } + }); + } + request(funct, handle, reg, len, cb, buffer); + return promise; } + // read a word from a big-endian device. + that.i2cReadWordDataBE = function (handle, reg, callback) { + return this._i2cRequestSwapWordResponse(I2CRW, handle, reg, 0, callback); + } + + // write a word to a little-endian device. that.i2cWriteWordData = function (handle, reg, word, callback) { - let wordarr = [word & 0xff, (word >> 8)&0xff, 0,0 ]; + let wordarr = [word & 0xff, (word >> 8)&0xff, 0,0 ]; // 4 bytes needed for pigpio. + let buffer = Buffer.from(wordarr); + return request(I2CWW, handle, reg, buffer.length, callback, buffer); + } + that.i2cWriteWordDataLE = that.i2cWriteWordData; + + // write a word to a big-endian device. + that.i2cWriteWordDataBE = function (handle, reg, word, callback) { + let wordarr = [(word >> 8)&0xff, word & 0xff, 0,0 ]; // 4 bytes needed for pigpio. let buffer = Buffer.from(wordarr); return request(I2CWW, handle, reg, buffer.length, callback, buffer); } - // await: [count, d0, d1, d2 ...] callback:(err, count, d0, d1, d2 ...) + + // this function receives an array back from pigpio, and removes the first byte (len) + // and then returns or resolves an array. + // the native request callback response returns a number of arguments, not an array... + // so this is more convenient. + // The response becomes: await: [d0, d1, d2 ...] or callback:(err, [d0, d1, d2 ...]) + that._i2cRequestProcessBlock = function(funct, handle, reg, len, callback, buffer){ + let cb; + let promise; + if (callback) { + cb = (err, ...args) => { + // discard count, as the count of args is the size of args... + if (args && args.length >= 1) + args.shift(); + callback(err, args); + } + } else { + promise = new Promise((resolve, reject) => { + cb = (error, ...args) => { + if (error) { + reject(error) + } else { + // discard count, as the count of args is the size of args... + args.shift(); + resolve(args); + } + } + }); + } + request(funct, handle, reg, len, cb, buffer); + return promise; + } + + // await: [d0, d1, d2 ...] callback:(err, [d0, d1, d2 ...]) + // smb read block data. no length specified. that.i2cReadBlockData = function (handle, reg, callback) { - return request(I2CRK, handle, reg, 0, callback); + return this._i2cRequestProcessBlock(I2CRK, handle, reg, 0, callback); } // 1-32 bytes @@ -711,11 +793,11 @@ exports.pigpio = function (pi) { } // read a block from reg with increment - // await: [count, d0, d1, d2 ...] callback:(err, count, d0, d1, d2 ...) + // await: [d0, d1, d2 ...] callback:(err, [d0, d1, d2 ...]) that.i2cReadI2cBlockData = function (handle, reg, len, callback) { - let lenarr = [len & 0xff, 0,0,0 ]; + let lenarr = [len & 0xff, 0,0,0 ]; // 4 bytes needed for pigpio. let buffer = Buffer.from(lenarr); - return request(I2CRI, handle, reg, buffer.length, callback, buffer); + return this._i2cRequestProcessBlock(I2CRI, handle, reg, buffer.length, callback, buffer); } that.i2cWriteI2cBlockData = function (handle, reg, data, callback) { @@ -723,20 +805,175 @@ exports.pigpio = function (pi) { return request(I2CWI, handle, reg, buffer.length, callback, buffer); } + // helpers to read/write blocks greater than 32 bytes.... + // pigpio protocol has a max of 32. + // set increment to true to increment reg read/written for each block. + // set to false if reading a single (non auto incrementing) reg (e.g. a fifo). + // let arr = await pigpio.i2cReadBigI2cBlock(handle, reg, len, true); or pigpio.i2cReadBigI2cBlock(handle, reg, len, true, (err, arr)=>{}, 16); + // let res = await pigpio.i2cWriteBigI2cBlock(handle, reg, true, arr|buf); or pigpio.i2cWriteBigI2cBlock(handle, reg, arr|buf, true, (err, res)=>{}, 16); + that.i2cReadBigI2cBlockData = function(handle, reg, len, increment, callback, chunksize){ + return this._i2cBigBlockFns('_i2cReadBigI2cBlockData', handle, reg, len, increment, callback, chunksize); + } + that.i2cWriteBigI2cBlockData = function(handle, reg, buffer, increment, callback, chunksize){ + return this._i2cBigBlockFns('_i2cWriteBigI2cBlockData', handle, reg, buffer, increment, callback, chunksize); + } + + that._i2cReadBigI2cBlockData = async function(handle, reg, len, increment, callback, chunksize){ + try{ + chunksize = chunksize || 32; + let buf = []; + let lenleft = len; + while (lenleft > 0) { + let thisread = lenleft; + if (thisread > chunksize) thisread = chunksize; /* set the output length */ + let partbuf = await this.i2cReadI2cBlockData(handle, reg, thisread); + if (increment) reg += thisread; + buf.push(...partbuf); + lenleft -= thisread; + } + callback(null, buf); + } catch (e){ + callback(e); + } + }; + that._i2cWriteBigI2cBlockData = async function(handle, reg, buffer, increment, callback, chunksize){ + try{ + chunksize = chunksize || 32; + let lenleft = buffer.length; + let index = 0; + while (lenleft > 0) { + let thiswrite = lenleft; + if (thiswrite > chunksize) thiswrite = chunksize; /* set the output length */ + await this.i2cWriteI2cBlockData(handle, reg, buffer.slice(index, index + thiswrite)); + if (increment) reg += thiswrite; + lenleft -= thiswrite; + index += thiswrite; + } + callback(null, index); + } catch (e){ + callback(e); + } + }; + // deal with callback or providing promise, whilst calling an async function. + that._i2cBigBlockFns = function(fn, handle, reg, a, b, callback, c, d){ + let cb = callback; + let promise; + if (!cb){ + promise = new Promise((resolve, reject) => { + cb = (error, ...args) => { + if (error) { + reject(error) + } else { + // discard count, as the count of args is the size of args... + resolve(args[0]); + } + } + }); + } + this[fn](handle, reg, a, b, cb, c, d); + return promise; + } + + // returns a word response. + // write/read a word from a little-endian device. that.i2cProcessCall = function (handle, reg, word, callback) { - let wordarr = [word & 0xff, (word >> 8)&0xff, 0, 0]; + let wordarr = [word & 0xff, (word >> 8)&0xff, 0, 0]; // 4 bytes needed for pigpio. let buffer = Buffer.from(wordarr); return request(I2CPC, handle, reg, buffer.length, callback, buffer); } + + // write/read a word from a big-endian device. + that.i2cProcessCallBE = function (handle, reg, word, callback) { + let wordarr = [(word >> 8)&0xff, word & 0xff, 0, 0]; // 4 bytes needed for pigpio. + let buffer = Buffer.from(wordarr); + return that._i2cRequestSwapWordResponse(I2CPC, handle, reg, buffer.length, callback, buffer); + } + - // writes 1-32 bytes of data, returns count, and buffer with data. - // await: [count, d0, d1, d2 ...] callback:(err, count, d0, d1, d2 ...) + // writes 1-32 bytes of data, returns or resolves an array + // await: [d0, d1, d2 ...] callback:(err, [d0, d1, d2 ...]) that.i2cBlockProcessCall = function (handle, reg, data, callback) { let buffer = Buffer.from(data); - return request(I2CPK, handle, reg, buffer.length, callback, buffer); + return this._i2cRequestProcessBlock(I2CPK, handle, reg, buffer.length, callback, buffer); + } + + ///////////////////////////////////////////////////////////////////// + // adds a function .i2c to pigpio. + // install with addI2cHelper(pigpio_instance); + // create an i2c instance like: + // let inst = await pigpio.i2c(bus, addr); + // or + // pigpio.i2c(bus, addr, (err, inst)=>{}); + // then + // let b = await inst.readByteData(reg); or inst.readByteData(reg, (err, byte)=>{}); + // implements all functions starting i2c in pigpio. + ///////////////////////////////////////////////////////////////////// + let addI2cHelper = function(pigpio_instance){ + let i2c = function(bus, addr, callback){ + let addfns = (instance)=>{ + let keys = Object.keys(instance.pigpio); + for (i = 0; i < keys.length; i++){ + let fnname = keys[i]; + if (fnname.startsWith('i2c')){ + if ((fnname !== 'i2cOpen') && (fnname !== 'i2cClose')){ + // convert i2cMyFn to i2c.myFn + instance[fnname.slice(3,4).toLowerCase() + fnname.slice(4)] = function(a,b,c,d,e,f){ + return this.pigpio[fnname](this.i2c, a,b,c,d,e,f); + } + } + } + } + }; + + let i2cinstance = { + bus:1, + i2c_address:0, + pigpio: pigpio_instance, + init: async function(bus, addr){ + this.bus = bus; + this.i2c_address = addr; + this.i2c = await this.pigpio.i2cOpen(this.bus, this.i2c_address); + addfns(this); + // keep open handles, maybe in the future we can cleanup? + this.pigpio._i2cs = this.pigpio._i2cs || {}; + this.pigpio._i2cs[this.i2c] = true; + return this; + }, + close: async function(){ + await this.pigpio.i2cClose(this.i2c); + delete this.pigpio._i2cs[this.i2c]; // forget this handle. + this.i2c = undefined; + } + }; + + + + let promise; + if (!callback){ + promise = new Promise((resolve, reject) => { + callback = (error, instance) => { + if (error) reject(error) + else resolve(instance); + } + }); + } + i2cinstance.init(bus, addr).then((instance)=>{ + callback(null, instance); + }).catch((e)=>{ + callback(e, null); + }); + return promise; + }; + + pigpio_instance.i2c = i2c; } + addI2cHelper(that); + // end of i2c master functions + ////////////////////////////////////////////////////////////////////////////////////// + + // pi as i2c slave? that.bscI2C = function (address, data, callback) { let control if (address > 0 && address < 128) { From 4d58b563e3ca28ab2dbf6da9044520024c6c74a9 Mon Sep 17 00:00:00 2001 From: btsimonh Date: Thu, 16 Feb 2023 08:33:43 +0000 Subject: [PATCH 6/9] enable promisified pigpio.end(). --- pigpio-client.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/pigpio-client.js b/pigpio-client.js index 5473c0f..69c53cc 100644 --- a/pigpio-client.js +++ b/pigpio-client.js @@ -633,9 +633,22 @@ exports.pigpio = function (pi) { that.end = function (cb) { commandSocket.end() // calls disconnectHandler, destroys connection. notificationSocket.end() // calls disconnectHandler, destroys connection. + let promise; + if (!cb){ + promise = new Promise((resolve, reject) => { + cb = (error, ...args) => { + if (error) { + reject(error) + } else { + resolve(args); + } + } + }); + } that.once('disconnected', () => { - if (typeof cb === 'function') cb() + if (typeof cb === 'function') cb(null, 0); }) + return promise; } From 292c36e74c256a6ddd607fcadc7202c278ec8b68 Mon Sep 17 00:00:00 2001 From: btsimonh Date: Thu, 16 Feb 2023 09:00:10 +0000 Subject: [PATCH 7/9] include flags in i2c helper function --- pigpio-client.js | 112 ++++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 54 deletions(-) diff --git a/pigpio-client.js b/pigpio-client.js index 69c53cc..8f2bafd 100644 --- a/pigpio-client.js +++ b/pigpio-client.js @@ -923,62 +923,66 @@ exports.pigpio = function (pi) { // implements all functions starting i2c in pigpio. ///////////////////////////////////////////////////////////////////// let addI2cHelper = function(pigpio_instance){ - let i2c = function(bus, addr, callback){ - let addfns = (instance)=>{ - let keys = Object.keys(instance.pigpio); - for (i = 0; i < keys.length; i++){ - let fnname = keys[i]; - if (fnname.startsWith('i2c')){ - if ((fnname !== 'i2cOpen') && (fnname !== 'i2cClose')){ - // convert i2cMyFn to i2c.myFn - instance[fnname.slice(3,4).toLowerCase() + fnname.slice(4)] = function(a,b,c,d,e,f){ - return this.pigpio[fnname](this.i2c, a,b,c,d,e,f); - } - } - } - } - }; - - let i2cinstance = { - bus:1, - i2c_address:0, - pigpio: pigpio_instance, - init: async function(bus, addr){ - this.bus = bus; - this.i2c_address = addr; - this.i2c = await this.pigpio.i2cOpen(this.bus, this.i2c_address); - addfns(this); - // keep open handles, maybe in the future we can cleanup? - this.pigpio._i2cs = this.pigpio._i2cs || {}; - this.pigpio._i2cs[this.i2c] = true; - return this; - }, - close: async function(){ - await this.pigpio.i2cClose(this.i2c); - delete this.pigpio._i2cs[this.i2c]; // forget this handle. - this.i2c = undefined; - } - }; - - + let i2c = function(bus, addr, flags, callback){ + if (typeof flags === 'function'){ + callback = flags; + flags = 0; // inits to zero + } + flags = flags || 0; + + let addfns = (instance)=>{ + let keys = Object.keys(instance.pigpio); + for (i = 0; i < keys.length; i++){ + let fnname = keys[i]; + if (fnname.startsWith('i2c')){ + if ((fnname !== 'i2cOpen') && (fnname !== 'i2cClose')){ + // convert i2cMyFn to i2c.myFn + instance[fnname.slice(3,4).toLowerCase() + fnname.slice(4)] = function(a,b,c,d,e,f){ + return this.pigpio[fnname](this.i2c, a,b,c,d,e,f); + } + } + } + } + }; + + let i2cinstance = { + bus:1, + i2c_address:0, + pigpio: pigpio_instance, + flags: flags, + init: async function(bus, addr){ + this.bus = bus; + this.i2c_address = addr; + this.i2c = await this.pigpio.i2cOpen(this.bus, this.i2c_address, this.flags); + addfns(this); + // keep open handles, maybe in the future we can cleanup? + this.pigpio._i2cs = this.pigpio._i2cs || {}; + this.pigpio._i2cs[this.i2c] = true; + return this; + }, + close: async function(){ + await this.pigpio.i2cClose(this.i2c); + delete this.pigpio._i2cs[this.i2c]; // forget this handle. + this.i2c = undefined; + } + }; - let promise; - if (!callback){ - promise = new Promise((resolve, reject) => { - callback = (error, instance) => { - if (error) reject(error) - else resolve(instance); - } - }); - } - i2cinstance.init(bus, addr).then((instance)=>{ - callback(null, instance); - }).catch((e)=>{ - callback(e, null); - }); - return promise; + let promise; + if (!callback){ + promise = new Promise((resolve, reject) => { + callback = (error, instance) => { + if (error) reject(error) + else resolve(instance); + } + }); + } + i2cinstance.init(bus, addr).then((instance)=>{ + callback(null, instance); + }).catch((e)=>{ + callback(e, null); + }); + return promise; }; - pigpio_instance.i2c = i2c; } addI2cHelper(that); From 74778bf70773f8b292a2b6c9e9ec78e931fa10bb Mon Sep 17 00:00:00 2001 From: btsimonh Date: Thu, 16 Feb 2023 09:01:25 +0000 Subject: [PATCH 8/9] update readme for i2c and i2c helper. --- readme.md | 52 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/readme.md b/readme.md index 5cb5136..4e52a5d 100644 --- a/readme.md +++ b/readme.md @@ -115,6 +115,10 @@ Note: Unless otherwise stated, all references to gpio pin numbers use **Broadcom **`pigpio.connect()`** Re-establishes communication with server after being disconnected. + +#### i2c Raw functions +These take a handle as the first parameter. + **`pigpio.i2cOpen(bus, address, flags?, callback)`** Return a handle for communication with a device attached to a bus on the I2C peripheral. `bus==0` uses (Broadcom) gpio 0 and 1, while `bus==1` use gpio 2 and 3 for SDA and SCL respectively. `address` takes values 1-127. @@ -122,13 +126,11 @@ May be called as `pigpio.i2cOpen(bus, address, callback)` - flags will default t **`pigpio.i2cClose(handle, callback)`** Close the I2C device associated with handle. -general note about returns with data. -if using await fn(), you will get an array back [count, d0, d1, d2 ...] -if using fn(callback), you will get (err, count, d0, d1, d2 ...) +general note about returns with data. For both callback and await, block functions will return an array. **`pigpio.i2cReadDevice(handle, count, callback)`** Read count bytes from the i2c -device referred by handle. Returns tuple (error, count, data). `error` is 0 on -success or an error code. `count` is the number of bytes read. `data` is a buffer. +device referred by handle. Returns tuple (error, data). `error` is 0 on +success or an error code. `data` is an array of size `count`. **`pigpio.i2cWriteDevice(handle, data, callback)`** Write data to the i2c device referred by handle. `data` is a byte array or utf8 string. Returns 0 if @@ -144,29 +146,55 @@ OK, otherwise an error code. **`pigpio.i2cWriteQuick(handle, bit, callback)`** Write a bit to a device -**`pigpio.i2cReadWordData(handle, reg, callback)`** Read a 16 bit word from a reg +**`pigpio.i2cReadWordData(handle, reg, callback)`** Read a 16 bit word from a reg (alias i2cReadWordDataLE) + +**`pigpio.i2cReadWordDataBE(handle, reg, callback)`** Read a 16 bit Big Endian word from a reg -**`pigpio.i2cWriteWordData(handle, reg, word, callback)`** Write a 16 bit word from a reg +**`pigpio.i2cWriteWordData(handle, reg, word, callback)`** Write a 16 bit word from a reg (alias i2cWriteWordDataLE) + +**`pigpio.i2cWriteWordDataBE(handle, reg, word, callback)`** Write a 16 bit Big Endian word from a reg **`pigpio.i2cReadBlockData(handle, reg, callback)`** Read a block from a reg -await: [count, d0, d1, d2 ...] callback:(err, count, d0, d1, d2 ...) +await: [d0, d1, d2 ...] callback:(err, [d0, d1, d2 ...]) -**`pigpio.i2cWriteBlockData(handle, reg, data, callback)`** Read a block to a reg +**`pigpio.i2cWriteBlockData(handle, reg, data, callback)`** Write a block to a reg 1-32 bytes as array, or anything which can be used by Buffer.from(var) **`pigpio.i2cReadI2cBlockData(handle, reg, len, callback)`** Read a block from reg with increment 1-32 bytes -await: [count, d0, d1, d2 ...] callback:(err, count, d0, d1, d2 ...) +await: [d0, d1, d2 ...] callback:(err, [d0, d1, d2 ...]) -**`pigpio.i2cWriteI2cBlockData(handle, reg, data, callback)`** Write a block from reg with increment +**`pigpio.i2cWriteI2cBlockData(handle, reg, data, callback)`** Write a block to reg with increment 1-32 bytes as array, or anything which can be used by Buffer.from(var) **`pigpio.i2cProcessCall = function (handle, reg, word, callback)`** Write a word (16 bit) returns a word (16 bit) response. +**`pigpio.i2cProcessCallBE = function (handle, reg, word, callback)`** Write a Big Endian word (16 bit) +returns a Big Endian word (16 bit) response. + **`pigpio.i2cBlockProcessCall(handle, reg, data, callback)`** Write a block to a reg, writes 1-32 bytes of data, returns data. -await: [count, d0, d1, d2 ...] callback:(err, count, d0, d1, d2 ...) +await: [d0, d1, d2 ...] callback:(err, [d0, d1, d2 ...]) + +**`pigpio.i2cReadBigI2cBlockData(handle, reg, len, increment?, callback, chunkSize?)`** Read a block from reg with or without increment, and at certain chunk sizes. +This is a convenience funciton which calls i2cReadI2cBlockData multiple times to read more than 32 bytes. Set increment to true if you want the reg to be incremented between calls. Set chunkSize if individual calls should be smaller than the default 32 bytes. +await: [d0, d1, d2 ...] callback:(err, [d0, d1, d2 ...]) + +**`pigpio.i2cWriteBigI2cBlockData(handle, reg, data, increment, callback, chunkSize)`** Write a block to reg with or without increment, and at certain chunk sizes. +This is a convenience funciton which calls i2cWriteI2cBlockData multiple times to write more than 32 bytes. Set increment to true if you want the reg to be incremented between calls. Set chunkSize if individual calls should be smaller than the default 32 bytes. +1-n bytes as array, or anything which can be used by Buffer.from(var) + +#### i2c Helper +**`pigpio.i2c(bus, address, flags?, callback)`** Create an i2c instance. +All the i2c functions can be called on the i2c instance, it just stored the handle for you. e.g. +``` +let i2c = await pigpio.i2c(bus, address); +let val = await i2c.readByteData(reg); // equivalent to pigpio.i2cReadByteData(handle, reg); +await i2c.close(); +``` + +#### i2c Slave **`pigpio.bscI2C(address, data, callback)`** Transfer data to/from the BSC I2C slave peripheral using gpio 18 (SDA) and 19 (SCL). The data bytes (if any) are From 313ff81a7f52d7ce15f211e682a9ffec3c849fd1 Mon Sep 17 00:00:00 2001 From: btsimonh Date: Thu, 16 Feb 2023 09:12:59 +0000 Subject: [PATCH 9/9] adjust i2c example for block read --- examples/i2cPCA9685Servos.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/i2cPCA9685Servos.js b/examples/i2cPCA9685Servos.js index b140aba..ae2727c 100644 --- a/examples/i2cPCA9685Servos.js +++ b/examples/i2cPCA9685Servos.js @@ -183,8 +183,7 @@ function addPCA9685Servos(pigpio_instance){ let l = (start+len) - i; if (l > 32) l = 32; let res = await pigpio.i2cReadI2cBlockData(this.pca, i, l); - console.log('bytes read: '+res[0]+' bytes:'+ res.toString()); - res.shift(); + console.log('bytes read: '+res.length+' bytes:'+ res.toString()); deviceData.push(...res); } for (let i = 0; i < deviceData.length; i+= 16){ @@ -274,9 +273,8 @@ function addPCA9685Servos(pigpio_instance){ // illustrate use of i2cReadI2cBlockData // note because await, we get an array back which starts with length let b = await pigpio.i2cReadI2cBlockData(this.pca, LED0_ON_L + LED_MULTIPLYER * servo, 4); - let len = b[0]; - let on = b[1] | (b[2]<<8); - let off = b[3] | (b[4] << 8); + let on = b[0] | (b[1]<<8); + let off = b[2] | (b[3] << 8); console.log({ on, off }); return {on, off};