fivdi / i2c-bus

I2C serial bus access with Node.js
MIT License
348 stars 57 forks source link

node-i2c .writeBytes(cmd, bytes) equivalent with i2c-bus ? #6

Closed SteadEXE closed 9 years ago

SteadEXE commented 9 years ago

Hello,

I totally rewrote adafruit-i2c-lcd which works with node-i2c, because it seems to be broken with latest version of node.js. I decided to use i2c-bus, but I don't found equivalent of wire.writeBytes(cmd, bytes); I tried:

var buf = new Buffer(values); bus.writeI2cBlockSync(this.ADDRESS, cmd, buf.length, buf);

But data length are over 32 bytes and it doesn't works. Do you have any idea about how can I fix it ?

Thanks guys.

fivdi commented 9 years ago

i2c-bus writeI2cBlockSync should work as a replacement for node-i2c writeBytes,

Under the covers, node-i2c writeBytes has the same 32 byte limitation as can be seen here, but it just ignores the 33rd byte and beyond. i2c-bus writeI2cBlockSync throws an error when passed more than 32 bytes.

Perhaps there's a logical error in the original adafruit-i2c-lcd or in the rewrite. Maybe in this section of code which handles the 32 byte limit specially?

SteadEXE commented 9 years ago

Can I give you the code I rewrote to got an external point of view, because it seems to not work as intended ?

Thanks for your reply :)

fivdi commented 9 years ago

Sure, add the code here in the issue.

SteadEXE commented 9 years ago

// Port expander registers var MCP23017_IOCON_BANK0 = 0x0A; // #IOCON when Bank 0 active var MCP23017_IOCON_BANK1 = 0x15; // #IOCON when Bank 1 active // These are register addresses when in Bank 1 only: var MCP23017_GPIOA = 0x09; var MCP23017_IODIRB = 0x10; var MCP23017_GPIOB = 0x19;

// LCD Commands var LCD_CLEARDISPLAY = 0x01; var LCD_RETURNHOME = 0x02; var LCD_ENTRYMODESET = 0x04; var LCD_DISPLAYCONTROL = 0x08; var LCD_CURSORSHIFT = 0x10; var LCD_FUNCTIONSET = 0x20; var LCD_SETCGRAMADDR = 0x40; var LCD_SETDDRAMADDR = 0x80;

// Flags for display on/off control var LCD_DISPLAYON = 0x04; var LCD_DISPLAYOFF = 0x00; var LCD_CURSORON = 0x02; var LCD_CURSOROFF = 0x00; var LCD_BLINKON = 0x01; var LCD_BLINKOFF = 0x00;

// Flags for display entry mode var LCD_ENTRYRIGHT = 0x00; var LCD_ENTRYLEFT = 0x02; var LCD_ENTRYSHIFTINCREMENT = 0x01; var LCD_ENTRYSHIFTDECREMENT = 0x00;

// Flags for display/cursor shift var LCD_DISPLAYMOVE = 0x08; var LCD_CURSORMOVE = 0x00; var LCD_MOVERIGHT = 0x04; var LCD_MOVELEFT = 0x00;

var flip = [ 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0C, 0x1C, 0x02, 0x12, 0x0A, 0x1A, 0x06, 0x16, 0x0E, 0x1E ];

var pollables = [ LCD_CLEARDISPLAY, LCD_RETURNHOME ];

var EventEmitter = require('events').EventEmitter; var I2C = require('i2c-bus');

var Plate = function(device, address, pollInterval) {

this.ADDRESS = address;
this.PORTA   = 0;
this.PORTB   = 0;
this.DDRB    = 0x10;
this.WIRE    = I2C.openSync(1);

this.BSTATE = 0;

this.colors = {
    OFF: 0x00,
    RED: 0x01,
    GREEEN: 0x02,
    YELLOW: 0x03,
    BLUE: 0x04,
    VIOLET: 0x05,
    TEAL: 0x06,
    WHITE: 0x07,
    ON: 0x07
}

this.buttons = {
    SELECT: 0x01,
    RIGHT: 0x02,
    DOWN: 0x04,
    UP: 0x08,
    LEFT: 0x10
}

this.clear = function() {
    this.writeByte(LCD_CLEARDISPLAY);
}

this.home = function() {
    this.writeByte(LCD_RETURNHOME);
}

this.close = function() {
    if (poll != null)
        clearInterval(poll);
}

this.backlight = function(colors) {
    this.PORTA = (this.PORTA & 0x3F)  | ((~colors & 0x3) << 6);
    this.PORTB = (this.PORTB & 0xFE)  | ((~colors & 0x4) >> 2);

    this.sendBytes(MCP23017_GPIOA, this.PORTA);
    this.sendBytes(MCP23017_GPIOB, this.PORTB);
}

this.message = function(text) {
    var lines = text.split('\n');

    for (var line in lines)
        if (line == 1)
            this.writeByte(0xC0);
        if (line < 2)
            this.writeByte(lines[line], true);
}

this.buttonState = function() {
    var ret = this.WIRE.readBytes(MCP23017_GPIOA, 1);
    ret = ret[0] & 0x1F;

    return ret;
}

this.init = function()
{
    this.sendBytes(MCP23017_IOCON_BANK1, 0);

    this.sendBytes(0, [
        0x3F,       // IODIRA    R+G LEDs=outputs, buttons=inputs
        this.DDRB,      // IODIRB    LCD D7=input, Blue LED=output
        0x3F,       // IPOLA     Invert polarity on button inputs
        0x0,        // IPOLB
        0x0,        // GPINTENA  Disable interrupt-on-change
        0x0,        // GPINTENB
        0x0,        // DEFVALA
        0x0,        // DEFVALB
        0x0,        // INTCONA
        0x0,        // INTCONB
        0x0,        // IOCON
        0x0,        // IOCON
        0x3F,       // GPPUA     Enable pull-ups on buttons
        0x0,        // GPPUB
        0x0,        // INTFA
        0x0,        // INTFB
        0x0,        // INTCAPA
        0x0,        // INTCAPB
        this.PORTA,         // GPIOA
        this.PORTB,         // GPIOB
        this.PORTA,         // OLATA     0 on all outputs; side effect of
        this.PORTB      // OLATB     turning on R+G+B backlight LEDs.
    ]);

    this.sendBytes(MCP23017_IOCON_BANK0, 0xA0);

    var displayshift   = LCD_CURSORMOVE | LCD_MOVERIGHT;
    var displaymode    = LCD_ENTRYLEFT  | LCD_ENTRYSHIFTDECREMENT;
    var displaycontrol = LCD_DISPLAYON  | LCD_CURSOROFF | LCD_BLINKOFF;

    this.writeByte(0x33);
    this.writeByte(0x32);
    this.writeByte(0x28);
    this.writeByte(LCD_CLEARDISPLAY);
    this.writeByte(LCD_CURSORSHIFT | displayshift);
    this.writeByte(LCD_ENTRYMODESET | displaymode);
    this.writeByte(LCD_DISPLAYCONTROL | displaycontrol);
    this.writeByte(LCD_RETURNHOME);

    this.clear();

    this.backlight(0x0);
}

this.sendBytes = function(cmd, values) {
    var cmd = new Buffer([ cmd ]);
    var bytes;

    if (values instanceof Array)
        bytes = new Buffer(values);
    else
        bytes = new Buffer([ values ]);

    var buffer = Buffer.concat([ cmd, bytes ]);

    this.WIRE.i2cWriteSync(this.ADDRESS, buffer.length, buffer);
}

this.sendByte = function(value) {
    this.WIRE.i2cWriteSync(this.ADDRESS, 1, value);
}

this.maskOut = function(bitmask, value) {
    hi = bitmask | flip[value >> 4];
    lo = bitmask | flip[value & 0x0F];

    return [ hi | 0x20, hi, lo | 0x20, lo ];
}

this.writeByte = function(value, char_mode) {
    var char_mode = char_mode || false;

    if (this.DDRB & 0x10)
    {
        var lo = (this.PORTB & 0x01) | 0x40;
        var hi = lo | 0x20;

        this.sendBytes(MCP23017_GPIOB, lo);

        var bits;

        do {
            this.sendByte(hi);

            bits = this.readByte();

            this.sendBytes(MCP23017_GPIOB, [lo, hi, lo])
        } while ((bits & 0x2) != 0);

        this.PORTB = lo;
        this.DDRB &= 0xEF;

        this.sendBytes(MCP23017_IODIRB, this.DDRB);
    }

    var bitmask = this.PORTB & 0x01;
        bitmask = (char_mode) ? bitmask | 0x80 : bitmask;

    if (value instanceof String)
    {
        var last = value.length - 1;
        var data = [];

        for (var k = 0; k <= last; k++)
        {
            if (value[k])
            {
                data = data.concat(this.maskOut(bitmask, value[k].charCodeAt(0)));

                if (data.length >= 32 || k == last)
                {
                    this.sendBytes(MCP23017_GPIOB, data);
                    this.PORTB = data[data.length - 1];
                    data = []
                }
            }
        }
    }
    else
    {
        data = this.maskOut(bitmask, value);
        this.sendBytes(MCP23017_GPIOB, data);
        this.PORTB = data[data.length - 1];
    }

    if(!char_mode && pollables.indexOf(value)!=-1)
    {
        this.DDRB |= 0x10;
        this.sendBytes(MCP23017_IODIRB, this.DDRB);
    }
}

this.readByte = function() {
    var _byte_ = new Buffer(1);

    this.WIRE.i2cReadSync(this.ADDRESS, 1, _byte_);

    return _byte_;
}

var pollInterval = pollInterval || 200;

/*if (pollInterval > 0)
{
    this.poll = setInterval(function() {
        var cur = this.buttonState();

        if (cur != this.BSTATE)
        {
            var key = this.BSTATE ^ cur;

            emit("button_change", key);

            if (cur < this.BSTATE)
                emit("button_up", key);
            else
                emit("button_down", key);

            this.BSTATE = cur;
        }
    }, pollInterval);
}*/

this.init();

}

module.exports = Plate;

SteadEXE commented 9 years ago

I tried with writeI2cBlockSync in sendBytes method but it throw an error. I tried to translate adafruit_i2c_lcd.coffee to javascript.

fivdi commented 9 years ago

I can't see any calls to writeI2cBlockSync in the above code but see that sendBytes is now using i2cWriteSync. What currently doesn't function correctly?

SteadEXE commented 9 years ago

// Port expander registers var MCP23017_IOCON_BANK0 = 0x0A; // #IOCON when Bank 0 active var MCP23017_IOCON_BANK1 = 0x15; // #IOCON when Bank 1 active // These are register addresses when in Bank 1 only: var MCP23017_GPIOA = 0x09; var MCP23017_IODIRB = 0x10; var MCP23017_GPIOB = 0x19;

// LCD Commands var LCD_CLEARDISPLAY = 0x01; var LCD_RETURNHOME = 0x02; var LCD_ENTRYMODESET = 0x04; var LCD_DISPLAYCONTROL = 0x08; var LCD_CURSORSHIFT = 0x10; var LCD_FUNCTIONSET = 0x20; var LCD_SETCGRAMADDR = 0x40; var LCD_SETDDRAMADDR = 0x80;

// Flags for display on/off control var LCD_DISPLAYON = 0x04; var LCD_DISPLAYOFF = 0x00; var LCD_CURSORON = 0x02; var LCD_CURSOROFF = 0x00; var LCD_BLINKON = 0x01; var LCD_BLINKOFF = 0x00;

// Flags for display entry mode var LCD_ENTRYRIGHT = 0x00; var LCD_ENTRYLEFT = 0x02; var LCD_ENTRYSHIFTINCREMENT = 0x01; var LCD_ENTRYSHIFTDECREMENT = 0x00;

// Flags for display/cursor shift var LCD_DISPLAYMOVE = 0x08; var LCD_CURSORMOVE = 0x00; var LCD_MOVERIGHT = 0x04; var LCD_MOVELEFT = 0x00;

var flip = [ 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0C, 0x1C, 0x02, 0x12, 0x0A, 0x1A, 0x06, 0x16, 0x0E, 0x1E ];

var pollables = [ LCD_CLEARDISPLAY, LCD_RETURNHOME ];

var EventEmitter = require('events').EventEmitter; var I2C = require('i2c-bus');

var Plate = function(device, address, pollInterval) {

this.ADDRESS = address;
this.PORTA   = 0;
this.PORTB   = 0;
this.DDRB    = 0x10;
this.WIRE    = I2C.openSync(1);

this.BSTATE = 0;

this.colors = {
    OFF: 0x00,
    RED: 0x01,
    GREEEN: 0x02,
    YELLOW: 0x03,
    BLUE: 0x04,
    VIOLET: 0x05,
    TEAL: 0x06,
    WHITE: 0x07,
    ON: 0x07
}

this.buttons = {
    SELECT: 0x01,
    RIGHT: 0x02,
    DOWN: 0x04,
    UP: 0x08,
    LEFT: 0x10
}

this.clear = function() {
    this.writeByte(LCD_CLEARDISPLAY);
}

this.home = function() {
    this.writeByte(LCD_RETURNHOME);
}

this.close = function() {
    if (poll != null)
        clearInterval(poll);
}

this.backlight = function(colors) {
    this.PORTA = (this.PORTA & 0x3F)  | ((~colors & 0x3) << 6);
    this.PORTB = (this.PORTB & 0xFE)  | ((~colors & 0x4) >> 2);

    this.sendBytes(MCP23017_GPIOA, this.PORTA);
    this.sendBytes(MCP23017_GPIOB, this.PORTB);
}

this.message = function(text) {
    var lines = text.split('\n');

    for (var line in lines)
        if (line == 1)
            this.writeByte(0xC0);
        if (line < 2)
            this.writeByte(lines[line], true);
}

this.buttonState = function() {
    var ret = this.WIRE.readBytes(MCP23017_GPIOA, 1);
    ret = ret[0] & 0x1F;

    return ret;
}

this.init = function()
{
    this.sendBytes(MCP23017_IOCON_BANK1, 0);

    this.sendBytes(0, [
        0x3F,       // IODIRA    R+G LEDs=outputs, buttons=inputs
        this.DDRB,      // IODIRB    LCD D7=input, Blue LED=output
        0x3F,       // IPOLA     Invert polarity on button inputs
        0x0,        // IPOLB
        0x0,        // GPINTENA  Disable interrupt-on-change
        0x0,        // GPINTENB
        0x0,        // DEFVALA
        0x0,        // DEFVALB
        0x0,        // INTCONA
        0x0,        // INTCONB
        0x0,        // IOCON
        0x0,        // IOCON
        0x3F,       // GPPUA     Enable pull-ups on buttons
        0x0,        // GPPUB
        0x0,        // INTFA
        0x0,        // INTFB
        0x0,        // INTCAPA
        0x0,        // INTCAPB
        this.PORTA,         // GPIOA
        this.PORTB,         // GPIOB
        this.PORTA,         // OLATA     0 on all outputs; side effect of
        this.PORTB      // OLATB     turning on R+G+B backlight LEDs.
    ]);

    this.sendBytes(MCP23017_IOCON_BANK0, 0xA0);

    var displayshift   = LCD_CURSORMOVE | LCD_MOVERIGHT;
    var displaymode    = LCD_ENTRYLEFT  | LCD_ENTRYSHIFTDECREMENT;
    var displaycontrol = LCD_DISPLAYON  | LCD_CURSOROFF | LCD_BLINKOFF;

    this.writeByte(0x33);
    this.writeByte(0x32);
    this.writeByte(0x28);
    this.writeByte(LCD_CLEARDISPLAY);
    this.writeByte(LCD_CURSORSHIFT | displayshift);
    this.writeByte(LCD_ENTRYMODESET | displaymode);
    this.writeByte(LCD_DISPLAYCONTROL | displaycontrol);
    this.writeByte(LCD_RETURNHOME);

    this.clear();

    this.backlight(0x0);
}

this.sendBytes = function(cmd, values) {

    var buffer;

    if (values instanceof Array)
        buffer = new Buffer(values);
    else
        buffer = new Buffer([ values ]);

    console.log(buffer);

    this.WIRE.writeI2cBlockSync(this.ADDRESS, cmd, buffer.length, buffer);
}

this.sendByte = function(value) {
    this.WIRE.i2cWriteSync(this.ADDRESS, 1, value);
}

this.maskOut = function(bitmask, value) {
    hi = bitmask | flip[value >> 4];
    lo = bitmask | flip[value & 0x0F];

    return [ hi | 0x20, hi, lo | 0x20, lo ];
}

this.writeByte = function(value, char_mode) {
    var char_mode = char_mode || false;

    if (this.DDRB & 0x10)
    {
        var lo = (this.PORTB & 0x01) | 0x40;
        var hi = lo | 0x20;

        this.sendBytes(MCP23017_GPIOB, lo);

        var bits;

        do {
            this.sendByte(hi);

            bits = this.readByte();

            this.sendBytes(MCP23017_GPIOB, [lo, hi, lo])
        } while ((bits & 0x2) != 0);

        this.PORTB = lo;
        this.DDRB &= 0xEF;

        this.sendBytes(MCP23017_IODIRB, this.DDRB);
    }

    var bitmask = this.PORTB & 0x01;
        bitmask = (char_mode) ? bitmask | 0x80 : bitmask;

    if (value instanceof String)
    {
        var last = value.length - 1;
        var data = [];

        for (var k = 0; k < last; k++)
        {
            if (value[k])
            {
                data = data.concat(this.maskOut(bitmask, value[k].charCodeAt(0)));

                if (data.length >= 32 || k == last)
                {
                    this.sendBytes(MCP23017_GPIOB, data);
                    this.PORTB = data[data.length - 1];
                    data = []
                }
            }
        }
    }
    else
    {
        data = this.maskOut(bitmask, value);
        this.sendBytes(MCP23017_GPIOB, data);
        this.PORTB = data[data.length - 1];
    }

    if(!char_mode && pollables.indexOf(value)!=-1)
    {
        this.DDRB |= 0x10;
        this.sendBytes(MCP23017_IODIRB, this.DDRB);
    }
}

this.readByte = function() {
    var _byte_ = new Buffer(1);

    this.WIRE.i2cReadSync(this.ADDRESS, 1, _byte_);

    return _byte_;
}

var pollInterval = pollInterval || 200;

/*if (pollInterval > 0)
{
    this.poll = setInterval(function() {
        var cur = this.buttonState();

        if (cur != this.BSTATE)
        {
            var key = this.BSTATE ^ cur;

            emit("button_change", key);

            if (cur < this.BSTATE)
                emit("button_up", key);
            else
                emit("button_down", key);

            this.BSTATE = cur;
        }
    }, pollInterval);
}*/

this.init();

}

module.exports = Plate;


I replaced "for (var k = 0; k <= last; k++)" by "for (var k = 0; k < last; k++)" It seems to work without throw exception.

Then on my main program I use: var LCDPlate = require("./LCD.js"); var LCD = new LCDPlate('/dev/i2c-1', 0x20);

LCD.backlight(th.colors.red); LCD.message("Hello world!");

On my PI the LCD turn on for 1 second and all LEDs are turning off and a special char is displayed. LEDs never turn red, and hello world is never displayed.

Thanks for help :-)

fivdi commented 9 years ago

Hmm, ...

Sorry, but I'm afraid I can't help you out here. There's too much code there for attempting to figure out what's going wrong.

fivdi commented 9 years ago

@Stead68 I'm going to close this one. If there's a concrete issue with i2c-bus, feel free to re-open or create a new issue.