UNPKG

bonescriptjtjk

Version:

Physical computing library for embedded Linux

430 lines (391 loc) 14.4 kB
var fs = require('fs'); var winston = require('winston'); var my = require('./my'); var parse = require('./parse'); var debug = process.env.DEBUG ? true : false; var gpioFile = {}; var pwmPrefix = {}; var ainPrefix = ""; exports.logfile = '/var/lib/cloud9/bonescript.log'; exports.readPWMFreqAndValue = function(pin, pwm) { var mode = {}; try { var period = fs.readFileSync(pwmPrefix[pin.pwm.name]+'/period'); var duty = fs.readFileSync(pwmPrefix[pin.pwm.name]+'/duty'); mode.freq = 1.0e9 / period; mode.value = duty / period; } catch(ex) { } return(mode); }; exports.readGPIODirection = function(n, gpio) { var mode = {}; var directionFile = "/sys/class/gpio/gpio" + n + "/direction"; if(my.file_existsSync(directionFile)) { mode.active = true; var direction = fs.readFileSync(directionFile, 'utf-8'); direction = direction.replace(/^\s+|\s+$/g, ''); mode.direction = direction; } return(mode); }; exports.readPinMux = function(pin, mode, callback) { var pinctrlFile = '/sys/kernel/debug/pinctrl/44e10800.pinmux/pins'; var muxRegOffset = parseInt(pin.muxRegOffset, 16); var readPinctrl = function(err, data) { if(err) { mode.err = 'readPinctrl error: ' + err; if(debug) winston.debug(mode.err); callback(mode); } mode = parse.modeFromPinctrl(data, muxRegOffset, 0x44e10800, mode); callback(mode); }; var tryPinctrl = function(exists) { if(exists) { fs.readFile(pinctrlFile, 'utf8', readPinctrl); } else { if(debug) winston.debug('getPinMode(' + pin.key + '): no valid mux data'); callback(mode); } }; if(callback) { my.file_exists(pinctrlFile, tryPinctrl); } else { try { var data2 = fs.readFileSync(pinctrlFile, 'utf8'); mode = parse.modeFromPinctrl(data2, muxRegOffset, 0x44e10800, mode); } catch(ex) { if(debug) winston.debug('getPinMode(' + pin.key + '): ' + ex); } } return(mode); }; exports.setPinMode = function(pin, pinData, template, resp, callback) { if(debug) winston.debug('hw.setPinMode(' + [pin.key, pinData, template, JSON.stringify(resp)] + ');'); if(debug) winston.debug('typeof callack = ' + typeof callback); if(template == 'bspm') { gpioFile[pin.key] = '/sys/class/gpio/gpio' + pin.gpio + '/value'; if(callback) { doCreateDT(resp); return(resp); } if(pin.led) { gpioFile[pin.key] = '/sys/class/leds/beaglebone::' + pin.led + '/brightness'; } } else if(template == 'bspwm') { if(callback) { my.load_dt('am33xx_pwm', null, resp, doCreateDT); return(resp); } if(!my.load_dt('am33xx_pwm')) { resp.err = 'Error loading am33xx_pwm devicetree overlay'; return(resp); } } else { resp.err = 'Unknown pin mode template'; if(callback) { callback(resp); return(resp); } } // only synchronous stuff at this point if(!my.create_dt(pin, pinData, template)) { resp.err = 'Error loading devicetree overlay for ' + pin.key + ' using template ' + template; return(resp); } if(template == 'bspwm') { try { var ocp = my.is_ocp(); var p = 'bs_pwm_test_' + pin.key; var pwm_test = my.find_sysfsFile(p, ocp, p + '.'); pwmPrefix[pin.pwm.name] = pwm_test; fs.writeFileSync(pwm_test+'/polarity', 0); } catch(ex) { resp.err = 'Error enabling PWM controls: ' + ex; winston.error(resp.err); } } // now to define the asynchronous calls function doCreateDT(resp) { if(resp.err) { callback(resp); return; } my.create_dt(pin, pinData, template, true, false, resp, onCreateDT); } function onCreateDT(resp) { if(resp.err) { callback(resp); return; } if(template == 'bspwm') { my.file_find('/sys/devices', 'ocp.', 1, onFindOCP); } else { callback(resp); } function onFindOCP(ocp) { if(ocp.err) { resp.err = "Error searching for ocp: " + ocp.err; if(debug) winston.debug(resp.err); callback(resp); return; } my.file_find(ocp.path, 'bs_pwm_test_' + pin.key + '.', 1, onFindPWM); } function onFindPWM(pwm_test) { if(pwm_test.err) { resp.err = "Error searching for pwm_test: " + pwm_test.err; if(debug) winston.debug(resp.err); callback(resp); return; } my.file_find(pwm_test.path, 'period', 1, onFindPeriod); function onFindPeriod(period) { if(period.err) { resp.err = "Error searching for period: " + period.err; if(debug) winston.debug(resp.err); callback(resp); return; } pwmPrefix[pin.pwm.name] = pwm_test.path; fs.writeFile(pwm_test.path+'/polarity', 0, 'ascii', onPolarityWrite); } } function onPolarityWrite(err) { if(err) { resp.err = "Error writing PWM polarity: " + err; if(debug) winston.debug(resp.err); } callback(resp); } } return(resp); }; exports.setLEDPinToGPIO = function(pin, resp) { var path = "/sys/class/leds/beaglebone:green:" + pin.led + "/trigger"; if(my.file_existsSync(path)) { fs.writeFileSync(path, "gpio"); } else { resp.err = "Unable to find LED " + pin.led; winston.error(resp.err); resp.value = false; } return(resp); }; exports.exportGPIOControls = function(pin, direction, resp, callback) { if(debug) winston.debug('hw.exportGPIOControls(' + [pin.key, direction, resp] + ');'); var n = pin.gpio; if(callback) { my.file_exists(gpioFile[pin.key], onFileExists); return; } var exists = my.file_existsSync(gpioFile[pin.key]); if(exists) { if(debug) winston.debug("gpio: " + n + " already exported."); fs.writeFileSync("/sys/class/gpio/gpio" + n + "/direction", direction, null); } else { try { if(debug) winston.debug("exporting gpio: " + n); fs.writeFileSync("/sys/class/gpio/export", "" + n, null); if(debug) winston.debug("setting gpio " + n + " direction to " + direction); fs.writeFileSync("/sys/class/gpio/gpio" + n + "/direction", direction, null); } catch(ex2) { resp.value = false; resp.err = 'Unable to export gpio-' + n + ': ' + ex2; if(debug) winston.debug(resp.err); var gpioUsers = fs.readFileSync('/sys/kernel/debug/gpio', 'utf-8'); gpioUsers = gpioUsers.split('\n'); } } function onFileExists(exists) { if(exists) { if(debug) winston.debug("gpio: " + n + " already exported."); fs.writeFile("/sys/class/gpio/gpio" + n + "/direction", direction, null, onGPIODirectionSet); } else { if(debug) winston.debug("exporting gpio: " + n); fs.writeFile("/sys/class/gpio/export", "" + n, null, onGPIOExport); } } function onGPIOExport(err) { if(err) onError(err); if(debug) winston.debug("setting gpio " + n + " direction to " + direction); fs.writeFile("/sys/class/gpio/gpio" + n + "/direction", direction, null, onGPIODirectionSet); } function onGPIODirectionSet(err) { if(err) onError(err); else callback(resp); } function onError(err) { resp.err = 'Unable to export gpio-' + n + ': ' + err; resp.value = false; if(debug) winston.debug(resp.err); findOwner(); } function findOwner() { fs.readFile('/sys/kernel/debug/gpio', 'utf-8', onGPIOUsers); } function onGPIOUsers(err, data) { if(!err) { var gpioUsers = data.split('\n'); for(var x in gpioUsers) { var y = gpioUsers[x].match(/gpio-(\d+)\s+\((\S+)\s*\)/); if(y && y[1] == n) { resp.err += '\nconsumed by ' + y[2]; if(debug) winston.debug(resp.err); } } } callback(resp); } return(resp); }; exports.writeGPIOValue = function(pin, value, callback) { if(typeof gpioFile[pin.key] == 'undefined') { gpioFile[pin.key] = '/sys/class/gpio/gpio' + pin.gpio + '/value'; if(pin.led) { gpioFile[pin.key] = "/sys/class/leds/beaglebone:"; gpioFile[pin.key] += "green:" + pin.led + "/brightness"; } if(!my.file_existsSync(gpioFile[pin.key])) { winston.error("Unable to find gpio: " + gpioFile[pin.key]); } } if(debug) winston.debug("gpioFile = " + gpioFile[pin.key]); if(callback) { fs.writeFile(gpioFile[pin.key], '' + value, null, callback); } else { try { fs.writeFileSync(gpioFile[pin.key], '' + value, null); } catch(ex) { winston.error("Unable to write to " + gpioFile[pin.key]); } } }; exports.readGPIOValue = function(pin, resp, callback) { var gpioFile = '/sys/class/gpio/gpio' + pin.gpio + '/value'; if(callback) { var readFile = function(err, data) { if(err) { resp.err = 'digitalRead error: ' + err; winston.error(resp.err); } resp.value = parseInt(data, 2); callback(resp); }; fs.readFile(gpioFile, readFile); return(true); } resp.value = parseInt(fs.readFileSync(gpioFile), 2); return(resp); }; exports.enableAIN = function(callback) { var helper = ""; if(my.load_dt('cape-bone-iio')) { var ocp = my.is_ocp(); if(ocp) { helper = my.find_sysfsFile('helper', ocp, 'helper.'); if(helper) { ainPrefix = helper + '/AIN'; } } } if(callback) { callback({'path': helper}) } return(helper.length > 1); }; exports.readAIN = function(pin, resp, callback) { var ainFile = ainPrefix + pin.ain.toString(); if(callback) { var readFile = function(err, data) { if(err) { resp.err = 'analogRead error: ' + err; winston.error(resp.err); } resp.value = parseInt(data, 10) / 1800; callback(resp); }; fs.readFile(ainFile, readFile); return(resp); } resp.value = parseInt(fs.readFileSync(ainFile), 10); if(isNaN(resp.value)) { resp.err = 'analogRead(' + pin.key + ') returned ' + resp.value; winston.error(resp.err); } resp.value = resp.value / 1800; if(isNaN(resp.value)) { resp.err = 'analogRead(' + pin.key + ') scaled to ' + resp.value; winston.error(resp.err); } return(resp); }; exports.writeGPIOEdge = function(pin, mode) { fs.writeFileSync('/sys/class/gpio/gpio' + pin.gpio + '/edge', mode); var resp = {}; resp.gpioFile = '/sys/class/gpio/gpio' + pin.gpio + '/value'; resp.valuefd = fs.openSync(resp.gpioFile, 'r'); resp.value = new Buffer(1); return(resp); }; exports.writePWMFreqAndValue = function(pin, pwm, freq, value, resp, callback) { if(debug) winston.debug('hw.writePWMFreqAndValue(' + [pin.key,pwm,freq,value,resp] + ');'); var path = pwmPrefix[pin.pwm.name]; try { var period = Math.round( 1.0e9 / freq ); // period in ns var duty = Math.round( period * value ); fs.writeFileSync(path+'/duty', 0); if(pwm.freq != freq) { if(debug) winston.debug('Updating PWM period: ' + period); fs.writeFileSync(path+'/period', period); } if(debug) winston.debug('Updating PWM duty: ' + duty); fs.writeFileSync(path+'/duty', duty); } catch(ex) { resp.err = 'error updating PWM freq and value: ' + path + ', ' + ex; winston.error(resp.err); } return(resp); }; exports.readEeproms = function(eeproms) { var boardName = fs.readFileSync(my.is_capemgr() + '/baseboard/board-name', 'ascii'); var version = fs.readFileSync(my.is_capemgr() + '/baseboard/revision', 'ascii'); var serialNumber = fs.readFileSync(my.is_capemgr() + '/baseboard/serial-number', 'ascii'); eeproms['/sys/bus/i2c/drivers/at24/1-0050/eeprom'] = {}; eeproms['/sys/bus/i2c/drivers/at24/1-0050/eeprom'].boardName = boardName; eeproms['/sys/bus/i2c/drivers/at24/1-0050/eeprom'].version = version; eeproms['/sys/bus/i2c/drivers/at24/1-0050/eeprom'].serialNumber = serialNumber; return(eeproms); }; exports.readPlatform = function(platform) { platform.name = fs.readFileSync(my.is_capemgr() + '/baseboard/board-name', 'ascii').trim(); if(platform.name == 'A335BONE') platform.name = 'BeagleBone'; if(platform.name == 'A335BNLT') platform.name = 'BeagleBone Black'; platform.version = fs.readFileSync(my.is_capemgr() + '/baseboard/revision', 'ascii').trim(); if(platform.version[0] == 0x1A) { platform.version = '1A'; platform.name = 'BeagleBone Green'; } else if(platform.version.match(/^GR/)) { platform.version = platform.version.substr(2); platform.name = 'BeagleBone Green'; } else if(!platform.version.match(/^[\040-\176]*$/)) delete platform.version; platform.serialNumber = fs.readFileSync(my.is_capemgr() + '/baseboard/serial-number', 'ascii').trim(); if(!platform.serialNumber.match(/^[\040-\176]*$/)) delete platform.serialNumber; return(platform); };