Wednesday, October 30, 2013

Implementing an I2c Workaround

The i2c library that I am using (kelly/node-i2c) works great...but...after some period of observations it causes node.js to fail with a segmentation fault.   I am not sure this is a problem with the base library or with how I am using it with the Analog Digital Converter that I am using.   I suspect that it is the latter but I don't have the technical skills to diagnose the problem.  Given the former I decided to implement a workaround as described below.

wireServer = require('child_process').fork('wireServer.js', 
   [global.config.i2cDevice, global.config.i2cAddress, global.config.i2cCommand]);
wireServerPid = wireServer.pid; 
utilities.trace(false, "test - wireServer started as PID " + wireServerPid);
Since failures generally only occurred after a period of time I decided to create a background process that could be started for the period of observation and then killed until the next period is started.  


eventEmitter.on('startObserve', function(message){
    wireServer.send({"message":"init", 
        "i2cDevice":global.config.i2cDevice,
        "i2cAddress":global.config.i2cAddress,
        "i2cCommand":global.config.i2cCommand});
    // Each message will be a voltage reading that we then pass to the below routine
    wireServer.on('message', function (message) {
        observe(message.voltageIn);
    });
});
I am using an event to start the observation period by sending a message to the wireServer process started above.   The message tells the server where to look for the I2c device.  Once this is done I setup a handler for readings coming back from the server.



execSync('kill ' + wireServerPid);
utilities.trace(false, "test - Current wireServer running as PID " + wireServerPid + " killed")
Once the I2c interface is started node will no longer respond to messages sent to the background process!   This means I have no way of asking it to die gracefully.  That being missing I use a little less graceful approach and kill it at the O/S level.

eventEmitter.emit('startObserve', '');
Finally we launch the observation perio.

The background process that the above launches, and then communicates with, is shown below:


// Load the library we need to get voltage measurements using i2c
var i2c = require('i2c');       
var i2cDevice = "/dev/i2c-" + process.argv[2];
var i2cAddress = process.argv[3];
var i2cCommand = Number(process.argv[4]);
// Convert the i2c address from character to hex
i2cAddress = parseInt("0x" + i2cAddress);
var wire = new i2c(i2cAddress, {device: i2cDevice, debug: false}); 
var seq = 0;

wire.on('data', function(data) {
    observe(data.data);
});

// Look for an init message from test to start our observations
process.on('message', function (message) {    
    wire.stream(i2cCommand, 4, 3);
});

// Take a voltage reading and send it on to test
function observe(buffer) {
    var voltageIn = 0;
    voltageIn = (buffer[0] << 8) + buffer[1];
    // Did we get a negative value?  If so make it a zero.
    if (voltageIn > 2048) {
        voltageIn = 0;
    }
    else {
        voltageIn = voltageIn / 2048;
    }
    if (seq == 5000 || seq === 0) {
        console.log(datetimeStamp() + " - wireServer - active");
        seq = 1;
    }
    process.send({seq:seq++, voltageIn: voltageIn });    
}

No comments:

Post a Comment