├── .gitignore ├── config ├── runtime.json ├── default.json └── external.js ├── lib ├── css │ └── config.css ├── index.js ├── js │ ├── BBUtils.js │ ├── IC74HC4067.js │ └── IC74HC595.js └── probe │ ├── InputBoard.js │ ├── OutputBoard.js │ ├── IOBoard.js │ └── BeagleBone.js ├── site_db ├── Tour │ └── .nothing ├── Page │ ├── index.json │ └── 404.json └── Site │ └── default.json ├── History.md ├── monitor.js ├── package.json ├── README.md ├── LICENSE └── pins.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /config/runtime.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/css/config.css: -------------------------------------------------------------------------------- 1 | .nm-app-beaglebone-heading { 2 | } 3 | -------------------------------------------------------------------------------- /site_db/Tour/.nothing: -------------------------------------------------------------------------------- 1 | Here for something in the directory 2 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 0.1.0 / 2 | ================== 3 | 4 | * Initial checkin 5 | -------------------------------------------------------------------------------- /monitor.js: -------------------------------------------------------------------------------- 1 | // Bootstrap for standalone development 2 | require('./lib/index'); 3 | require('monitor'); 4 | -------------------------------------------------------------------------------- /site_db/Page/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "/app/beaglebone/index", 3 | "title": "Home - BeagleBone Monitor" 4 | } -------------------------------------------------------------------------------- /site_db/Site/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "default", 3 | "name": "Node Monitor", 4 | "logo": "/static/css/default/images/monitor.jpg", 5 | "favicon": "/static/css/default/images/favicon.ico", 6 | "css": "", 7 | "tours": [] 8 | } -------------------------------------------------------------------------------- /config/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "Monitor": { 3 | "appName": "beaglebone-monitor", 4 | "allowExternalConnections": true, 5 | "consoleLogListener": { 6 | "pattern": "{debug,trace,info,warn,error,fatal}.*" 7 | } /* */, 8 | "autoStart": { 9 | "beaglebone": { 10 | "probeName": "bb-test", "probeClass": "BeagleBone", "initParams":{ 11 | "pins": [ 12 | {"id":"USR1", "name":"test1", "direction":"in", "pollMs":1000}, 13 | {"id":"USR2", "name":"test2", "direction":"out", "value":1} 14 | ] 15 | } 16 | } 17 | } 18 | /* */ 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "beaglebone-monitor", 3 | "description": "BeagleBone", 4 | "version": "0.1.0", 5 | "main": "lib/index.js", 6 | "author": "Loren West ", 7 | "homepage": "http://lorenwest.github.com/beaglebone-monitor/", 8 | "licenses": ["MIT"], 9 | "repository": { 10 | "type" : "git", 11 | "url" : "http://github.com/lorenwest/beaglebone-monitor.git" 12 | }, 13 | "dependencies": { 14 | "connect": ">=2.13.0 < 2.14.0", 15 | "bonescript": ">=0.2.4", 16 | "monitor": ">=0.6.9 <0.7.0", 17 | "monitor-dashboard": ">=0.6.0 <0.7.0" 18 | }, 19 | "devDependencies": { 20 | }, 21 | "engines": {"node": ">0.10.x"}, 22 | "scripts": { 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /config/external.js: -------------------------------------------------------------------------------- 1 | // Configuration overrides when NODE_ENV=external 2 | // Read the comments below before using this configuration. 3 | module.exports = { 4 | 5 | // Overrides for the monitor-min package 6 | Monitor: { 7 | 8 | // This setting allows incoming monitor connections from remote systems. 9 | // It should be used only after assuring the network security policies 10 | // prevent untrusted connections on the monitor service port range (usually 42000+). 11 | allowExternalConnections: true 12 | }, 13 | 14 | // Overrides for the node-monitor application 15 | Dashboard: { 16 | 17 | // This setting allows incoming browser connections from remote systems. 18 | // It should be used only after assuring the network security policies 19 | // prevent untrusted connections on the application service port (usually 4200). 20 | allowExternalConnections: true 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | beaglebone-monitor 2 | ================== 3 | 4 | I/O Monitoring for the BeagleBone 5 | 6 | FEATURES 7 | ======== 8 | 9 | * Remote representation and control 10 | * Microcontroller abstraction (possible?) 11 | * BeagleBone probe (singleton to run representing the BB) 12 | * MultiInput board probe (multi-instance - for controlling a MUX) 13 | * MultiOutput board probe (multi-instance - for controlling a 7401) 14 | * Examples using auto-start probes, data model probes, recipes 15 | 16 | MICROCONTROLLER PROBE (beaglebone, arduino, raspberry pi) 17 | (Abstracts GPIO, SPI, access) 18 | 19 | * BBProbe 20 | * Singleton (opens a server port to be sure) 21 | * Reserve/Assign IO pins by client 22 | * Offer a pin-managed interface to higher level probes 23 | * Offer direct interface to non-managed pins 24 | 25 | Microcontroller app 26 | * Configures the BB Probe 27 | * Configures all I/O probes 28 | * Configures all recipes 29 | 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Loren West and other contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | // This is run when the app is loaded from monitor-dashboard 2 | (function(root){ 3 | 4 | // Create a server, and expose this directory 5 | var Monitor = global.Monitor, 6 | Connect = require('connect'), 7 | FS = require('fs'), 8 | Path = require('path'), 9 | Static = Connect['static'](__dirname); 10 | 11 | // Load all probes found in the ./probe directory 12 | // This is synchronous because require() is synchronous 13 | FS.readdirSync(Path.join(__dirname, 'probe')).forEach(function(fileName) { 14 | if (fileName.substr(-3) === '.js') { 15 | require('./probe/' + fileName); 16 | } 17 | }); 18 | 19 | // Export a middleware component 20 | var app = module.exports = function(request, response, next) { 21 | 22 | // Process dynamic app endpoints here 23 | if (request.url === '/status') { 24 | response.writeHead(200, {'Content-Type': 'text/plan'}); 25 | return response.end('ok'); 26 | } 27 | 28 | // Forward to the static endpoint, then to the next step 29 | // if the file isn't there. The next step is a monitor page. 30 | return Static(request, response, next); 31 | } 32 | 33 | }(this)); 34 | -------------------------------------------------------------------------------- /site_db/Page/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "/404", 3 | "title": "New Page Template", 4 | "components": [ 5 | { 6 | "id": "c1", 7 | "viewClass": "core.Html", 8 | "viewOptions": { 9 | "htmlValue": "Page not found.
Create a monitor page at this location?" 10 | }, 11 | "monitor": {}, 12 | "css": { 13 | ".nm-cv": "top:60px; left:0px; z-index:1;", 14 | ".nm-cv-viewport": "font-size:20px; line-height:34px; height:78px; width:367px;" 15 | } 16 | }, 17 | { 18 | "id": "c2", 19 | "viewClass": "core.Button", 20 | "viewOptions": { 21 | "label": "Create Page", 22 | "icon": "icon-magic", 23 | "onPress": "pageView.newPage();" 24 | }, 25 | "monitor": {}, 26 | "css": { 27 | ".nm-cv": "top:170px; left:120px; z-index:2;" 28 | } 29 | }, 30 | { 31 | "id": "c3", 32 | "viewClass": "core.Button", 33 | "viewOptions": { 34 | "label": "Back", 35 | "icon": "icon-arrow-left", 36 | "onPress": "window.history.back();" 37 | }, 38 | "monitor": {}, 39 | "css": { 40 | ".nm-cv": "top:170px; left:0px; z-index:3;" 41 | } 42 | } 43 | ] 44 | } -------------------------------------------------------------------------------- /lib/js/BBUtils.js: -------------------------------------------------------------------------------- 1 | var b = require('bonescript'); 2 | 3 | /** 4 | * General purpose beaglebone utilities 5 | * 6 | * 7 | * Serial UART info: 8 | * 9 | * UART0: only used for serial debugging, going through the USB port next to 10 | * the power supply plug - can't be used by your programs 11 | * UART3: pins are not available on the expansion headers can't be easily 12 | * used by your programs 13 | * UART5: only has RX and TX pins (no CTS and RTS pins available) 14 | * 15 | * UART RX TX CTS RTS 16 | * UART1 P9_26, Mode: 0 P9_24, Mode: 0 P9_20, Mode: 0 P9_19, Mode: 0 17 | * UART2 P9_22, Mode: 1 P9_21, Mode: 1 P8_37, Mode: 6 P8_38, Mode: 6 18 | * UART4 P9_11, Mode: 6 P9_13, Mode: 6 P8_35, Mode: 6 P8_33, Mode: 6 19 | * UART5 P8_38, Mode: 4 P8_37, Mode: 4 - - 20 | */ 21 | 22 | var BBUtil = module.exports = {}; // Hash of static functions. Not a class 23 | 24 | /** 25 | * Initialize up a group of GPIO pins 26 | * 27 | * This sets the pin modes and default values for the specified GPIO pins 28 | * 29 | * @static 30 | * @method 31 | * @initGPIO 32 | * @param pins {[Object]} - An array of (or one) GPIO pin definitions 33 | * @param pins.name - Name of the pin 34 | * @param pins.direction - One of b.INPUT or b.OUTPUT 35 | * @param [pins.value] - Initial value (for b.OUTPUT). One of b.HIGH or b.LOW 36 | * @param [pins.pull='pullup'] - One of 'pullup', 'pulldown', or 'disabled' 37 | * @param [pins.slew='fast'] - One of 'fast' or 'slow' 38 | * @param callback {function(error)} - Callback when complete 39 | */ 40 | BBUtil.initGPIO = function(pins, callback) { 41 | 42 | // Make an array, and default callback 43 | pins = Array.isArray(pins) ? pins : [pins]; 44 | callback = callback || function(){}; 45 | 46 | // Set up each pin sequentially 47 | var setPin = function(currentPin) { 48 | var pin = pins[currentPin], 49 | pull = pin.pull ? pin.pull : 'pullup', 50 | slew = pin.slew ? pin.slew : 'fast'; 51 | 52 | // Set the mode 53 | b.pinMode(pin.name, pin.direction, 7, pull, slew, function(err) { 54 | var nextPin = currentPin + 1; 55 | if (err && err.err) { 56 | return callback({err: err, msg: 'Error setting the pin mode for: ' + pin.name}); 57 | } 58 | 59 | // Set the initial value? 60 | if (pin.direction === b.OUTPUT && pin.value) { 61 | b.digitalWrite(pin.name, pin.value, function(err) { 62 | if (err & err.err) { 63 | return callback({ 64 | err: err, 65 | msg: 'Error setting initial value for: ' + pin.name}); 66 | } 67 | 68 | // Process the next pin, or callback if done 69 | if (nextPin < pins.length) { 70 | setPin(nextPin); 71 | } else { 72 | callback(); 73 | } 74 | }); 75 | return; 76 | } 77 | 78 | // Not an output pin. Process next pin, or callback. 79 | if (nextPin < pins.length) { 80 | setPin(nextPin); 81 | } else { 82 | callback(); 83 | } 84 | }); 85 | }; 86 | 87 | // Invoke for the first pin 88 | setPin(0); 89 | }; 90 | 91 | /** 92 | * Read an analog value (overridden from BB.analogRead) 93 | * 94 | * There is a bug in the ADC controller where the value read is actually 95 | * the prior value read. The analogRead method must be called twice, with 96 | * the second value returned. 97 | * 98 | * @static 99 | * @method 100 | * @analogRead 101 | * @param pin {String} - Name of the ADC input pin 102 | * @param callback {function(x)} - Same as BB.analogRead 103 | */ 104 | BBUtil.analogRead = function(pin, callback) { 105 | values = []; 106 | // This throws away the first one, and averages the subsequent 3 107 | b.analogRead(pin, function(x) { 108 | b.analogRead(pin, function(x) { 109 | values.push(x.value); 110 | b.analogRead(pin, function(x) { 111 | values.push(x.value); 112 | b.analogRead(pin, function(x) { 113 | values.push(x.value); 114 | x.value = (values[0] + values[1] + values[2]) / 3; 115 | callback(x); 116 | }); 117 | }); 118 | }); 119 | }); 120 | }; 121 | -------------------------------------------------------------------------------- /lib/js/IC74HC4067.js: -------------------------------------------------------------------------------- 1 | 2 | var b = require('bonescript'); 3 | var BBUtils = require('./BBUtils'); 4 | 5 | /** 6 | * This module drives the 74HC4067 16-channel analog mixer 7 | * or the 74HC4051 8 channel equivalent 8 | * 9 | * This IC acts like a rotary switch, switching in/out voltage 10 | * from pin 1 (common I/O) through I0-I15. 11 | * 12 | * Data Sheet: http://bit.ly/1ayDaoB 13 | * Tutorial: http://bit.ly/13zjBdf 14 | * 15 | * IC layout: 16 | * 17 | * PIN 1 | Common I/O 18 | * PIN 12 | Ground 19 | * PIN 24 | Driver VCC (2-6vdc) 20 | * PIN 15 | Enable Flow (VCC=Disable, GND=Enable) 21 | * PIN 10,11,14,13 | Data Switch 0-3 (respectively) 22 | * PIN 9-2 | I/O 0-7 (respectively) 23 | * PIN 23-16 | I/O 8-15 (respectively) 24 | * 25 | * Hardware assembly notes: 26 | * 27 | * Tie 15 (Enable) to ground for flow, VCC to stop flow to current switch 28 | * 29 | * See the data switch for switch voltage and amperage ratings 30 | * 31 | * @class IC74HC4067 32 | * @constructor 33 | * @param config {Object} IC Configuration 34 | * @param config.pins {Object} Pin definitions 35 | * @param config.pins.data0 {String} BB data0 pin name ex: "P9_18" 36 | * @param config.pins.data1 {String} BB data1 pin name ex: "P9_19" 37 | * @param config.[pins.data2=''] {String} BB data2 pin name ex: "P9_20" 38 | * @param config.[pins.data3=''] {String} BB data3 pin name ex: "P9_21" 39 | * @param config.[pins.enable] {String} Enable pin name ex: "P9_22" 40 | * @param [enabled=true] {Boolean} Initial enabled true/false 41 | * @param [position=0] {int} Current switch position (0-15) 42 | * @param [callback] {function(error)} Callback to run after initialization 43 | */ 44 | var IC74HC4067 = module.exports = function(config, callback) { 45 | var t = this; 46 | t.pins = {}; 47 | t.pins.data0 = config.pins.data0; 48 | t.pins.data1 = config.pins.data1; 49 | t.pins.data2 = config.pins.data2 || ''; 50 | t.pins.data3 = config.pins.data3 || ''; 51 | t.pins.enable = config.pins.enable || ''; 52 | t.enabled = config.enabled; 53 | t.position = config.position || 0; 54 | callback = callback || function(){}; 55 | 56 | // Set the pin I/O modes 57 | t._setPinModes(function(error) { 58 | if (error) { 59 | return callback(error); 60 | } 61 | 62 | // Set initial enable/disable 63 | t.enable(t.enabled, function(error) { 64 | if (error) { 65 | return callback(error); 66 | } 67 | 68 | // Set initial switch position 69 | t.switch(t.position, function(error) { 70 | if (error) { 71 | return callback(error); 72 | } 73 | callback(); 74 | }); 75 | }); 76 | }); 77 | 78 | }; 79 | 80 | /** 81 | * Set the BB pin modes 82 | * 83 | * This sets all pins to GPIO OUTPUT 84 | * 85 | * @private 86 | * @method 87 | * @_setPinModes 88 | * @param callback {Function(err)} 89 | */ 90 | IC74HC4067.prototype._setPinModes = function(callback) { 91 | 92 | // Set the pin modes 93 | var t = this; 94 | 95 | // Set up the GPIO pins 96 | var modes = [ 97 | {name: t.pins.data0, direction: b.OUTPUT, value: b.LOW}, 98 | {name: t.pins.data1, direction: b.OUTPUT, value: b.LOW} 99 | ]; 100 | 101 | // Set the optional pins 102 | if (t.pins.data2) { 103 | modes.push({name: t.pins.data2, direction: b.OUTPUT, value: b.LOW}); 104 | } 105 | if (t.pins.data3) { 106 | modes.push({name: t.pins.data3, direction: b.OUTPUT, value: b.LOW}); 107 | } 108 | if (t.pins.enable) { 109 | modes.push({name: t.pins.enable, direction: b.OUTPUT, value: b.LOW}); 110 | } 111 | 112 | // Initialize the BB pins 113 | BBUtils.initGPIO(modes, callback); 114 | 115 | }; 116 | 117 | /** 118 | * Enable (or disable) flow to the common I/O pin 119 | * 120 | * @method 121 | * @enable 122 | * @param [enabled=true] {Boolean} Enable the flow? 123 | * @param [callback] {Function(err)} 124 | */ 125 | IC74HC4067.prototype.enable = function(enabled, callback) { 126 | var t = this; 127 | 128 | // Process optional params 129 | if (typeof(enabled) === 'function') { 130 | callback = enabled; 131 | } 132 | callback = callback || function(){}; 133 | 134 | // Default enabled to true; 135 | if (typeof(enabled) !== 'boolean') { 136 | enabled = true; 137 | } 138 | 139 | // Don't process if the enabled pin isn't configured 140 | if (!t.pins.enable) { 141 | return callback(); 142 | } 143 | 144 | // Tie pin 15 (enable) LOW to enable, HIGH to disable 145 | var pinValue = enabled ? b.LOW : b.HIGH; 146 | b.digitalWrite(t.pins.enable, pinValue, function(err) { 147 | if (err && err.err) { 148 | return callback({err: err.err, msg: 'Error enabling IC74HC4067'}); 149 | } 150 | t.enabled = enabled; 151 | callback(); 152 | }); 153 | }; 154 | 155 | /** 156 | * Switch the I/O to the specified I/O number 157 | * 158 | * @method 159 | * @switch 160 | * @param position {Int} Pin number to switch to (0-15) 161 | * @param callback {Function(err)} 162 | */ 163 | IC74HC4067.prototype.switch = function(position, callback, numCalls) { 164 | var t = this; 165 | callback = callback || function(){}; 166 | 167 | // Precondition - value must be in the range 168 | if (position < 0 || 169 | (!t.pins.data2 && position > 3) || 170 | (!t.pins.data3 && position > 7) || 171 | (position > 15)) { 172 | return callback({err: 'RANGE', msg: 'Value out of range for IC74HC4067: ' + position}); 173 | } 174 | 175 | // Called when a pin is set 176 | var numPinsLeft = 0; 177 | var didError = false; 178 | var whenSet = function(err) { 179 | 180 | // Process error (no-op if already errored) 181 | if (didError) {return;} 182 | if (err && err.err) { 183 | didError = true; 184 | return callback(err.err); 185 | } 186 | 187 | // Callback if this is the last pin 188 | if (--numPinsLeft === 0) { 189 | t.position = position; 190 | return callback(); 191 | } 192 | 193 | // Still processing pins 194 | return; 195 | }; 196 | 197 | // Set b.HIGH or b.LOW based on truthy 198 | function highOrLow(value) { 199 | return value ? b.HIGH : b.LOW; 200 | } 201 | 202 | // Set pins asynchronously in parallel 203 | numPinsLeft++; 204 | b.digitalWrite(t.pins.data0, highOrLow(position & 0x1), whenSet); 205 | numPinsLeft++; 206 | b.digitalWrite(t.pins.data1, highOrLow(position & 0x2), whenSet); 207 | if (t.pins.data2) { 208 | numPinsLeft++; 209 | b.digitalWrite(t.pins.data2, highOrLow(position & 0x4), whenSet); 210 | if (t.pins.data3) { 211 | numPinsLeft++; 212 | b.digitalWrite(t.pins.data3, highOrLow(position & 0x8), whenSet); 213 | } 214 | } 215 | }; 216 | -------------------------------------------------------------------------------- /lib/probe/InputBoard.js: -------------------------------------------------------------------------------- 1 | // InputBoard.js (c) 2013-2014 Loren West 2 | // May be freely distributed under the MIT license. 3 | // For further details and documentation: 4 | // http://lorenwest.github.com/beaglebone-monitor 5 | var Monitor = require('monitor'), 6 | Probe = Monitor.Probe, 7 | Config = Monitor.Config, 8 | Bonescript = require('bonescript'), 9 | bonePins = Bonescript.bone.pins, 10 | BBUtils = require('../js/BBUtils'), 11 | IC4067 = require('../js/IC74HC4067'), 12 | logger = Monitor.getLogger('InputBoard'); 13 | 14 | /** 15 | * The input board controls a 4051 8 channel mux or a 4067 16 channel mux. 16 | * This board uses 4 GPIO pins to poll for up to 16 inputs. 17 | * 18 | * IO Board Wire Color BeagleBone 19 | * ------------|-----------------|------------------------------------------- 20 | * Ground | Orange Stripe | Ground 21 | * +3.3v | Orange | +3.3v (Vcc or 3v3) 22 | * Input | Green Stripe | (specified in initParams.pins) 23 | * +1.8v | Blue | +1.8v (Va - Max analog reference voltage) 24 | * Data0 | Blue Stripe | (specified in initParams.pins) 25 | * Data1 | Green | (specified in initParams.pins) 26 | * Data2 | Brown Stripe | (specified in initParams.pins) 27 | * Data3 | Brown | (specified in initParams.pins) 28 | * 29 | * @class InputBoard 30 | * @constructor 31 | * @param initParams {Object} Probe initialization parameters 32 | * @param [initParams.bbProbeName] {String} probeName of the BB probe 33 | * @param [initParams.pollMs=1000] {Integer} Polling timer interval 34 | * @param initParams.pins {Object} BeagleBone I/O pin IDs (ex: P9_22) 35 | * @param initParams.pins.data0 {String} BB GPIO Pin number for data 0 36 | * @param initParams.pins.data1 {String} BB GPIO Pin number for data 1 37 | * @param [initParams.pins.data2] {String} BB GPIO Pin number for data 2 38 | * @param [initParams.pins.data3] {String} BB GPIO Pin number for data 3 39 | * @param initParams.pins.input {String} Pin number for digital or analog input. 40 | * If this is one of the analog input pins then analog values 41 | * between 0 and 1 are provided. Otherwise 0 or 1 are provided. 42 | * @param initParams.inputs {Object Array} Array defining all inputs 43 | * @param initParams.inputs.n.name {String} Name of the probe variable to use 44 | * @param [initParams.inputs.n.description] {String} Human description of the input 45 | * @param [initParams.inputs.n.precision=3] {Number} Number of digits to retain 46 | * past the decimal point (rounded). Dry contacts use 0 (for 0/1) 47 | */ 48 | var InputBoard = Probe.extend({ 49 | 50 | probeClass: 'InputBoard', 51 | 52 | // Called by Backbone.Model on object construction 53 | initialize: function(attributes, options){ 54 | var t = this; 55 | 56 | // Assume callback responsibility 57 | options.asyncInit = true; 58 | var callback = options.callback; 59 | 60 | // Assign instance data 61 | t.pins = attributes.pins; 62 | t.pollMs = (typeof attributes.pollMs === 'undefined') ? 1000 : attributes.pollMs; 63 | t.inputs = attributes.inputs; 64 | t.numInputs = t.inputs.length; 65 | t.ic = null; 66 | t.isAnalogInput = bonePins[t.pins.input].ain !== 'undefined'; 67 | t.readFn = t.isAnalogInput ? BBUtils.analogRead : Bonescript.digitalRead; 68 | t.timer = null; // Timer before next heartbeat 69 | t.cyanide = false; 70 | t.heartbeatFn = function(){t.nextHeartbeat();}; 71 | t.inHeartbeat = false; 72 | 73 | // Build the named data model elements 74 | t.inputs.forEach(function(input){ 75 | t.set(input.name, 0, {silent:true}); 76 | }); 77 | 78 | // Connect a monitor to the beaglebone probe 79 | var initBBMonitor = function() { 80 | Bonescript.getPlatform(function(platform) { 81 | if (!platform.serialNumber) { 82 | logger.info('initialize', 'No beaglebone detected. Running in emulation mode.'); 83 | } 84 | t.emulationMode = platform.serialNumber ? false : true; 85 | t.set('emulationMode', t.emulationMode); 86 | t.bbMonitor = null; 87 | if (attributes.bbProbeName) { 88 | t.bbMonitor = new Monitor({probeName: attributes.bbProbeName}); 89 | t.bbMonitor.connect(function(error) { 90 | if (error) { 91 | logger.error('4067init.bbMonitor', error); 92 | return callback(error); 93 | } 94 | initIC(); 95 | }); 96 | } 97 | else { 98 | initIC(); 99 | } 100 | }); 101 | }; 102 | 103 | // Initialize the IC. 104 | var initIC = function() { 105 | if (t.emulationMode) { 106 | return callback(); 107 | } 108 | t.ic = new IC4067({pins:t.pins}, function(error) { 109 | if (error) { 110 | logger.error('4067init.ic', error); 111 | return callback(error); 112 | } 113 | // Perform the first full heartbeat, and callback from initialize 114 | // once all inputs have been read. 115 | t.nextHeartbeat(callback); 116 | }); 117 | }; 118 | 119 | // Initialize the input pin unless analog 120 | if (t.isAnalogInput) { 121 | initBBMonitor(); 122 | } 123 | else { 124 | var modes = [{name: t.pins.input, direction: Bonescript.INPUT}]; 125 | BBUtils.initGPIO(modes, function(error) { 126 | if (error) { 127 | logger.error('GPIO Init', error); 128 | return callback(error); 129 | } 130 | initBBMonitor(); 131 | }); 132 | } 133 | }, 134 | 135 | // Shut down the probe 136 | release: function() { 137 | var t = this; 138 | if (t.timer) { 139 | clearTimeout(t.timer); 140 | t.timer = null; 141 | } 142 | else { 143 | t.cyanide = true; 144 | } 145 | }, 146 | 147 | // Heartbeat processing. One heartbeat reads all inputs. 148 | // At the end of a heartbeat, it sleeps for the configured 149 | // interval, and calls the heartbeat again. 150 | nextHeartbeat: function(callback) { 151 | var t = this, 152 | rotateInput = null, 153 | readInput = null, 154 | startStamp = Date.now(); 155 | 156 | // Don't heartbeat if we're already heartbeating 157 | if (t.inHeartbeat) { 158 | logger.error('nextHeartbeat', 'BUG: nextHeartbeat called during an existing heartbeat'); 159 | return; 160 | } 161 | 162 | // Reset the timer 163 | if (t.timer) { 164 | clearTimeout(t.timer); 165 | t.timer = null; 166 | } 167 | 168 | // Read input at the specified input location 169 | readInput = function(inputNum) { 170 | 171 | // We're done with the heartbeat 172 | if (inputNum >= t.numInputs) { 173 | 174 | // Set up for the next heartbeat, or stop the heart 175 | if (!t.cyanide) { 176 | t.timer = setTimeout(t.heartbeatFn, t.pollMs); 177 | } 178 | 179 | if (callback) { 180 | callback(); 181 | } 182 | return; 183 | } 184 | 185 | // Set the mux to the proper input 186 | t.ic.switch(inputNum, function(err) { 187 | if (err) { 188 | logger.error('muxSwitch', err); 189 | return callback(err); 190 | } 191 | 192 | // Read the mux at this position 193 | t.readFn(t.pins.input, function(x) { 194 | if (x.err) { 195 | logger.error('readInput', {msg:'Error reading input', err:x.err}); 196 | return callback(x.err); 197 | } 198 | 199 | // Set the input value if it's different. 200 | // This triggers a change immediately. 201 | var attrName = t.inputs[inputNum].name; 202 | var precision = t.inputs[inputNum].precision; 203 | precision = typeof precision === 'undefined' ? 3 : precision; 204 | var attrValue = +x.value.toFixed(precision); 205 | if (t.get(attrName) !== attrValue) { 206 | t.set(attrName, attrValue); 207 | if (t.bbMonitor) { 208 | t.bbMonitor.set(attrName, attrValue); 209 | } 210 | } 211 | 212 | // Get the next value 213 | readInput(++inputNum); 214 | }); 215 | }); 216 | } 217 | 218 | // Start by reading input 0 219 | readInput(0); 220 | } 221 | 222 | }); 223 | -------------------------------------------------------------------------------- /lib/probe/OutputBoard.js: -------------------------------------------------------------------------------- 1 | // OutputBoard.js (c) 2013-2014 Loren West 2 | // May be freely distributed under the MIT license. 3 | // For further details and documentation: 4 | // http://lorenwest.github.com/beaglebone-monitor 5 | var Monitor = require('monitor'), 6 | Probe = Monitor.Probe, 7 | Config = Monitor.Config, 8 | Bonescript = require('bonescript'), 9 | BBUtils = require('../js/BBUtils'), 10 | IC595 = require('../js/IC74HC595'), 11 | logger = Monitor.getLogger('OutputBoard'); 12 | 13 | /** 14 | * The output board is a series of 74HC595 chips, attached to the main board 15 | * with an ethernet cable. 16 | * 17 | * It can host any number of digital outputs, 8 per 595 chip. 18 | * 19 | * It uses 4 GPIO ports (3 if the initial output isn't important) 20 | * 21 | * IO Board Wire Color BeagleBone 22 | * ------------|-----------------|------------------------------------------- 23 | * Ground | Orange Stripe | Ground 24 | * +3.3v | Orange | +3.3v (Vcc or 3v3) 25 | * +5v | Green Stripe | +5v (Vin) 26 | * data | Blue | (specified in initParams.pins) 27 | * clock | Blue Stripe | (specified in initParams.pins) 28 | * latch | Green | (specified in initParams.pins) 29 | * enable | Brown Stripe | (specified in initParams.pins) 30 | * not used | Brown | not used 31 | * 32 | * For more information about the board design, see: [TODO] 33 | * 34 | * @class OutputBoard 35 | * @constructor 36 | * @param initParams {Object} Probe initialization parameters 37 | * @param [initParams.bbProbeName] {String} probeName of the BB probe 38 | * @param initParams.pins {Object} BeagleBone I/O pin IDs (ex: P9_22) 39 | * @param initParams.pins.data {String} Pin number for ic595 data 40 | * @param initParams.pins.clock {String} Pin number for ic595 clock 41 | * @param initParams.pins.latch {String} Pin number for ic595 latch 42 | * @param [initParams.pins.enable] {String} Pin number for ic595 enable 43 | * @param initParams.outputs {Object Array} Array defining all output positions. 44 | * @param initParams.outputs.n.name {String} Name of the probe variable to use 45 | * @param [initParams.outputs.n.description] {String} Human description of the input 46 | * @param [initParams.outputs.n.inverse=false] {Boolean} Inverse 0/1? Useful for relay module 47 | * @param [initParams.outputs.n.initialValue=0] {Integer} Initial output value (0 or 1) 48 | */ 49 | var OutputBoard = Probe.extend({ 50 | 51 | probeClass: 'OutputBoard', 52 | 53 | // Called by Backbone.Model on object construction 54 | initialize: function(attributes, options){ 55 | var t = this; 56 | 57 | // Assume callback responsibility 58 | options.asyncInit = true; 59 | var callback = options.callback; 60 | 61 | // Assign instance data 62 | t.pins = attributes.pins; 63 | t.outputs = attributes.outputs; 64 | t.numOutputs = t.outputs.length; 65 | t.num595chips = Math.ceil(t.numOutputs / 8); 66 | t.ic595 = null; 67 | t.bbMonitor = null; 68 | t.validOutputNames = []; 69 | t.ic595Array = []; // One element per 595 chip 70 | t.isDisabled = true; 71 | t.isSendingNow = false; 72 | 73 | // Initialize the 959 array with zeros 74 | for (var i = 0; i < t.num595chips; i++) { 75 | t.ic595Array.push(0x00); 76 | } 77 | 78 | // Connect a monitor to the beaglebone probe 79 | var initBBMonitor = function() { 80 | Bonescript.getPlatform(function(platform) { 81 | if (!platform.serialNumber) { 82 | logger.info('initialize', 'No beaglebone detected. Running in emulation mode.'); 83 | } 84 | t.emulationMode = platform.serialNumber ? false : true; 85 | t.set('emulationMode', t.emulationMode); 86 | t.bbMonitor = null; 87 | if (attributes.bbProbeName) { 88 | t.bbMonitor = new Monitor({probeName: attributes.bbProbeName}); 89 | t.bbMonitor.connect(function(error) { 90 | if (error) { 91 | logger.error('595init.bbMonitor', error); 92 | return callback(error); 93 | } 94 | initIC(); 95 | t.bbMonitor.on('change', t.onBBChange, t); 96 | }); 97 | } 98 | else { 99 | initIC(); 100 | } 101 | }); 102 | }; 103 | 104 | // Called to initialize the IC 105 | var initIC = function() { 106 | if (t.emulationMode) { 107 | return callback(); 108 | } 109 | 110 | // Initialize the 595 library, but keep the chips disabled until 111 | // the values are set. 112 | t.isSendingNow = true; 113 | t.ic595 = new IC595({pins: t.pins, values:t.ic595Array, enabled:false}, function(error) { 114 | t.isSendingNow = false; 115 | if (error) { 116 | logger.error('595init', error); 117 | return callback(error); 118 | } 119 | 120 | // Build the named data model elements 121 | var outputs = {}; // key=name, value=value 122 | t.outputs.forEach(function(output){ 123 | t.validOutputNames.push(output.name); 124 | outputs[output.name] = output.initialValue ? 1 : 0; 125 | }); 126 | 127 | // Now set output values 128 | t.set_control(outputs, callback); 129 | }); 130 | }; 131 | 132 | initBBMonitor(); 133 | }, 134 | 135 | // Send the current output states to the 595 array 136 | sendOutputs: function(callback) { 137 | var t = this; 138 | 139 | // If sending now, wait a second and try again 140 | if (t.isSendingNow) { 141 | setTimeout(function(){t.sendOutputs(callback)},1000); 142 | return; 143 | } 144 | t.isSendingNow = true; 145 | 146 | // Set each output value 147 | for (var i = 0; i < t.outputs.length; i++) { 148 | var value = t.get(t.outputs[i].name); 149 | if (typeof value === 'undefined') { 150 | value = 0; 151 | } 152 | if (t.outputs[i].inverse) { 153 | value = value ? 0 : 1; 154 | } 155 | t.ic595.set(i, value); 156 | } 157 | 158 | // Now shift them out 159 | t.ic595.shiftOut(function(error){ 160 | t.isSendingNow = false; 161 | if (error) { 162 | return callback(error); 163 | } 164 | 165 | // If the 595 is disabled, enable it now 166 | if (t.isDisabled) { 167 | t.isDisabled = false; 168 | return t.ic595.enableOutput(callback); 169 | } 170 | callback(); 171 | }); 172 | }, 173 | 174 | /** 175 | * Enable or disable the output board pins 176 | * 177 | * @method enable_control 178 | * @param enabled {boolean} Enabled or disabled (t/f) 179 | * @param callback {function(err)} Called when done or error 180 | */ 181 | enable_control: function(params, callback) { 182 | var t = this; 183 | callback = callback || function(){}; 184 | if (typeof(params.enabled) === 'undefined' || params.enabled) { 185 | t.ic595.enableOutput(callback); 186 | } 187 | else { 188 | t.ic595.disableOutput(callback); 189 | } 190 | }, 191 | 192 | /** 193 | * Called when the monitored BB changes 194 | * 195 | * This allows control of this probe by setting the attribute in the BB probe 196 | */ 197 | onBBChange: function() { 198 | var t = this, 199 | changes = {}; 200 | t.validOutputNames.forEach(function(attrName) { 201 | var attrValue = t.bbMonitor.get(attrName); 202 | if (attrValue !== t.get(attrName)) { 203 | changes[attrName] = attrValue; 204 | } 205 | }); 206 | if (Monitor._.size(changes)) { 207 | t.set_control(changes); 208 | } 209 | }, 210 | 211 | /** 212 | * Remotely set an output via set 213 | * 214 | * This overrides Probe.set_control for settable monitor attributes. It allows 215 | * setting pin values by using the remote model.set() method. 216 | * 217 | * @method set_control 218 | * @param outputs {Object} Name/value outputs to set into the probe. Only names 219 | * defined as outputs can be set by this control, and 220 | * only 0 or 1 are valid values. 221 | * @param callback {Function(error)} Called when the attributes are set or error 222 | */ 223 | set_control: function(outputs, callback) { 224 | var t = this; 225 | callback = callback || function(){}; 226 | 227 | // Validate the param names and values 228 | var value = null; 229 | for (var paramName in outputs) { 230 | if (t.validOutputNames.indexOf(paramName) < 0) { 231 | var err = {msg: 'Invalid output param: "' + paramName + '"'}; 232 | logger.error('setOutputs', err); 233 | return callback(err); 234 | } 235 | value = outputs[paramName]; 236 | if (value !== 0 && value !== 1) { 237 | var err = {msg: 'Invalid output value (must be 0 or 1)', value: value}; 238 | logger.error('setOutputs', err); 239 | return callback(err); 240 | } 241 | } 242 | 243 | // Set the output in this model for sendOutputs 244 | t.set(outputs, {quiet:true}); 245 | 246 | // Send outputs to the ICs 247 | t.sendOutputs(function(){ 248 | 249 | // Publish the output values now 250 | t.set(outputs); 251 | 252 | // Set the values in the central BB probe 253 | if (t.bbMonitor) { 254 | t.bbMonitor.set(outputs); 255 | } 256 | 257 | // We're done 258 | callback(); 259 | }); 260 | } 261 | 262 | }); 263 | -------------------------------------------------------------------------------- /lib/js/IC74HC595.js: -------------------------------------------------------------------------------- 1 | var b = require('bonescript'); 2 | var BBUtils = require('./BBUtils'); 3 | 4 | /** 5 | * This module drives the 74HC595 8-bit shift register. 6 | * 7 | * IC layout: 8 | * 9 | * PIN 15, 1-7 | Out0-7 | Output pins 0-7 10 | * PIN 8 | GND | Ground (-) 11 | * PIN 9 | Out7" | Chain - Serial out (for chaining to data in) 12 | * PIN 10 | MR | Clear - Master Reclear (active low) 13 | * PIN 11 | SH_CP | Clock - Shift Register Clock Pin 14 | * PIN 12 | ST_CP | Latch - Storage Register Clock Pin 15 | * PIN 13 | OE | Enable - Output Enable (low=enable, high=disable) 16 | * PIN 14 | SER | Data - Serial Data 17 | * PIN 16 | +VCC | Supply voltage (+3v3) 18 | * 19 | * Hardware assembly notes: 20 | * 21 | * Always tie MR (master reclear) to +VCC. 22 | * 23 | * Pins are random on power-on, suggest attaching a 10kOhm resistor 24 | * from OE (output enable) to +VCC, and using the OE enable pin 25 | * if intial state is important. It can be quite a while between 26 | * power-on and this script running. 27 | * 28 | * Suggest using 4 GPIOs: Data, Clock, Latch, and Enable 29 | * 30 | * 3 GPIOs if power-on setting isn't important: Data, Clock, Latch 31 | * (tie OE to ground) 32 | * 33 | * Software notes: 34 | * 35 | * Initial value passed into init determines number of chips chained 36 | * together. A small int (max 0xFF) drives one chip, otherwise an 37 | * array of small ints (max 0xFF) drives multiple chained ICs 38 | * 39 | * @class IC74HC595 40 | * @constructor 41 | * @param config {object} Configuration 42 | * @param config.pins {Object} Pin definitions 43 | * @param config.pins.data {String} Data pin name ex: "P9_18" 44 | * @param config.pins.clock {String} Clock pin name ex: "P9_22" 45 | * @param config.pins.latch {String} Latch pin name ex: "P9_17" 46 | * @param [config.pins.enable] {String} Enable (OE) pin name ex: "P9_21" 47 | * @param [config.pins.clear] {String} Hardware Clear (MR) pin name ex: "P9_19" 48 | * @param config.values {int or [int]} Initial pin values. A single small int for 49 | * driving one chip, an array of int values for multiple chained chips. 50 | * @param [config.enabled=true] {boolean} Enable on initialization? 51 | * @param [callback] {function(error)} Callback to run after initialization 52 | */ 53 | var IC74HC595 = module.exports = function(config, callback) { 54 | var t = this, 55 | enable = typeof config.enabled === 'undefined' ? true : config.enabled; 56 | t.config = config; 57 | t.pins = config.pins; 58 | t.values = Array.isArray(config.values) ? config.values : [config.values]; 59 | callback = callback || function(){}; 60 | 61 | // Set the pin modes and initial state, then shift out the initial values 62 | t._setPinModes(function(error) { 63 | if (error) { 64 | return callback(error); 65 | } 66 | 67 | function shiftInitialValues() { 68 | t.shiftOut(function(error) { 69 | if (error) { 70 | return callback(error); 71 | } 72 | if (enable) { 73 | t.enableOutput(callback); 74 | } 75 | else { 76 | callback(); 77 | } 78 | }); 79 | } 80 | 81 | // Disable if requested, then shift initial values 82 | if (!enable) { 83 | t.disableOutput(shiftInitialValues); 84 | } 85 | else { 86 | shiftInitialValues(); 87 | } 88 | 89 | }); 90 | }; 91 | 92 | /** 93 | * Set the BB pin modes 94 | * 95 | * This sets all pins to GPIO OUTPUT 96 | * 97 | * @private 98 | * @method 99 | * @_setPinModes 100 | * @param callback {Function(err)} 101 | */ 102 | IC74HC595.prototype._setPinModes = function(callback) { 103 | 104 | // Set the pin modes 105 | var t = this, 106 | numPins = 0; 107 | 108 | // Set up the GPIO pins 109 | var modes = [ 110 | {name: t.pins.data, direction: b.OUTPUT, value: b.LOW}, 111 | {name: t.pins.clock, direction: b.OUTPUT, value: b.LOW}, 112 | {name: t.pins.latch, direction: b.OUTPUT, value: b.LOW} 113 | ]; 114 | 115 | // Don't define the enable pin until enabling. Otherwise flicker occurs. 116 | 117 | // If clear is defined, set initial value to NOT clear 118 | if (t.pins.clear) { 119 | modes.push({name: t.pins.clear, direction: b.OUTPUT, value: b.HIGH}); 120 | } 121 | BBUtils.initGPIO(modes, callback); 122 | 123 | }; 124 | 125 | /** 126 | * Sets the value of the specified output pin to b.HIGH or b.LOW 127 | * 128 | * You must call shiftOut() after setting to shift the new values out. 129 | * 130 | * @method 131 | * @set 132 | * @param pin {Number} Pin number (0-n) 133 | * @return {ENUM} either b.LOW (0) or b.HIGH (1) 134 | */ 135 | IC74HC595.prototype.set = function(pin, value) { 136 | var t = this; 137 | var chipNum = Math.floor(pin / 8); 138 | var chipValue = t.values[chipNum]; 139 | var pin = pin % 8; // pin within the chip 140 | var mask = Math.pow(2,pin); 141 | 142 | // Set or clear 143 | if (value) { 144 | chipValue = chipValue | mask; // set 145 | } 146 | else { 147 | chipValue = chipValue & ~mask; // clear 148 | } 149 | t.values[chipNum] = chipValue; 150 | } 151 | 152 | /** 153 | * Gets the current value of the specified pin 154 | * 155 | * @method 156 | * @get 157 | * @param pin {Number} Pin number (0-n) 158 | * @return {ENUM} either b.LOW (0) or b.HIGH (1) 159 | */ 160 | IC74HC595.prototype.get = function(pin) { 161 | var t = this; 162 | var chipNum = Math.floor(pin / 8); 163 | var chipValue = t.values[chipNum]; 164 | var pin = pin % 8; // pin within the chip 165 | var mask = Math.pow(2,pin); 166 | return chipValue & mask ? b.HIGH : b.LOW; 167 | } 168 | 169 | /** 170 | * Shift the current values out to the chip(s), starting with the last 171 | * 595 in the array, and ending with the first 595 in the array. 172 | * 173 | * @method 174 | * @shiftOut 175 | * @param callback {Function(err)} 176 | */ 177 | IC74HC595.prototype.shiftOut = function(callback) { 178 | var t = this; 179 | callback = callback || function(){}; 180 | 181 | // Shift out a full 595 chip 182 | var shift = function(chipNumber) { 183 | var value = t.values[chipNumber]; 184 | b.shiftOut(t.pins.data, t.pins.clock, b.MSBFIRST, value, function(err) { 185 | var nextChip = chipNumber - 1; 186 | if (err) { 187 | return callback({err:x.err, msg:'Error shifting data out ' + t.pins.data}); 188 | } 189 | if (nextChip >= 0) { 190 | return shift(nextChip); 191 | } 192 | 193 | // Done shifting out. Latch now. 194 | t._latch(callback); 195 | }); 196 | } 197 | 198 | // Shift out the last chip first 199 | shift(t.values.length - 1); 200 | }; 201 | 202 | /** 203 | * Latch the current values into the registers 204 | * 205 | * @private 206 | * @method 207 | * @_latch 208 | * @param callback {Function(err)} 209 | */ 210 | IC74HC595.prototype._latch = function(callback) { 211 | var t = this; 212 | 213 | // Set the latch HIGH, then LOW 214 | b.digitalWrite(t.pins.latch, b.HIGH, function(err) { 215 | if (err && err.err) { 216 | return callback({err: err, msg: 'Error latching HIGH IC74HC595 registers'}); 217 | } 218 | b.digitalWrite(t.pins.latch, b.LOW, function(err) { 219 | if (err && err.err) { 220 | return callback({err: err, msg: 'Error latching LOW IC74HC595 registers'}); 221 | } 222 | callback(); 223 | }); 224 | }); 225 | }; 226 | 227 | /** 228 | * Enable the output pins 229 | * 230 | * This sets the enable pin low (enabling) if not enabled. 231 | * 232 | * @method 233 | * @enableOutput 234 | * @param callback {Function(err)} 235 | */ 236 | IC74HC595.prototype.enableOutput = function(callback) { 237 | var t = this; 238 | callback = callback || function(){}; 239 | 240 | // No-op if if no enable pin defined 241 | if (!t.pins.enable) { 242 | return callback(); 243 | } 244 | 245 | // Initialize the GPIO pin if not done before 246 | if (t.enabled === undefined) { 247 | BBUtils.initGPIO({name: t.pins.enable, direction: b.OUTPUT, value:b.LOW}, function(err) { 248 | if (err && err.err) { 249 | return callback({err: err, msg: 'Error enabling IC74HC595 output'}); 250 | } 251 | t.enabled = true; 252 | return callback(); 253 | }); 254 | return; 255 | } 256 | 257 | // GPIO is initialized. 258 | b.digitalWrite(t.pins.enable, b.LOW, function(err) { 259 | if (err && err.err) { 260 | return callback({err: err, msg: 'Error enabling IC74HC595 output'}); 261 | } 262 | t.enabled = true; 263 | return callback(); 264 | }); 265 | }; 266 | 267 | /** 268 | * Disable the output pins 269 | * 270 | * This sets the enable pin high (disabling) if enabled. 271 | * 272 | * @method 273 | * @disableOutput 274 | * @param callback {Function(err)} 275 | */ 276 | IC74HC595.prototype.disableOutput = function(callback) { 277 | var t = this; 278 | callback = callback || function(){}; 279 | 280 | // No-op if no enable pin defined 281 | if (!t.pins.enable) { 282 | return callback(); 283 | } 284 | 285 | // Initialize the GPIO pin if not done before 286 | if (t.enabled === undefined) { 287 | BBUtils.initGPIO({name: t.pins.enable, direction: b.OUTPUT, value:b.HIGH}, function(err) { 288 | if (err && err.err) { 289 | return callback({err: err, msg: 'Error disabling IC74HC595 output'}); 290 | } 291 | t.enabled = false; 292 | return callback(); 293 | }); 294 | return; 295 | } 296 | 297 | // GPIO is initialized. 298 | b.digitalWrite(t.pins.enable, b.HIGH, function(err) { 299 | if (err && err.err) { 300 | return callback({err: err, msg: 'Error disabling IC74HC595 output'}); 301 | } 302 | t.enabled = false; 303 | return callback(); 304 | }); 305 | }; 306 | 307 | /** 308 | * Hardware Clear 309 | * 310 | * This performs a hardware clear if the clear pin is defined, otherwise 311 | * it performs a software clear (setting all to zero); 312 | * 313 | * @method 314 | * @clearOutput 315 | * @param callback {Function(err)} 316 | */ 317 | IC74HC595.prototype.clearOutput = function(callback) { 318 | var t = this; 319 | callback = callback || function(){}; 320 | 321 | // Software clear if no hardware clear pin defined 322 | if (!t.pins.clear) { 323 | for (var i = 0; i < t.values.length; i++) {t.values[i] = 0;} 324 | return t.shiftOut(callback); 325 | } 326 | 327 | // Set the clear LOW, then HIGH 328 | b.digitalWrite(t.pins.clear, b.LOW, function(err) { 329 | if (err && err.err) { 330 | return callback({err: err, msg: 'Error clearing LOW IC74HC595'}); 331 | } 332 | b.digitalWrite(t.pins.clear, b.HIGH, function(err) { 333 | if (err && err.err) { 334 | return callback({err: err, msg: 'Error clearing HIGH IC74HC595'}); 335 | } 336 | return callback(); 337 | }); 338 | }); 339 | }; 340 | -------------------------------------------------------------------------------- /lib/probe/IOBoard.js: -------------------------------------------------------------------------------- 1 | // IOBoard.js (c) 2013-2014 Loren West 2 | // May be freely distributed under the MIT license. 3 | // For further details and documentation: 4 | // http://lorenwest.github.com/beaglebone-monitor 5 | var Monitor = require('monitor'), 6 | Probe = Monitor.Probe, 7 | Config = Monitor.Config, 8 | Bonescript = require('bonescript'), 9 | BBUtils = require('../js/BBUtils'), 10 | IC595 = require('../js/IC74HC595'), 11 | logger = Monitor.getLogger('IOBoard'); 12 | 13 | // Constants 14 | ANALOG_INPUT_PINS = ['P9_33','P9_35','P9_36','P9_37','P9_38','P9_39','P9_40']; 15 | 16 | /** 17 | * The I/O board is a tradeoff of speed for a single cable. Use it when: 18 | * 19 | * 1) You need both inputs and outputs 20 | * 2) You want only 1 ethernet cable vs 1 for input, 1 for output 21 | * 3) You don't mind waiting 1 second to scan 16 inputs 22 | * 23 | * The remote IO board is a custom board designed to provide up to 24 | * 16 digital and/or analog inputs, and any number of digital outputs. 25 | * 26 | * It's a combination of an InputBoard and and OutputBoard, where the first 27 | * chip of output controls the input. 28 | * 29 | * IO Board Wire Color BeagleBone 30 | * ------------|-----------------|------------------------------------------- 31 | * Ground | Orange Stripe | Ground 32 | * +3.3v | Orange | +3.3v (Vcc or 3v3) 33 | * +5v | Green Stripe | +5v (Vin) 34 | * +1.8v | Blue | +1.8v (Va - Max analog reference voltage) 35 | * ic595 data | Blue Stripe | (specified in initParams.pins) 36 | * ic595 clock | Green | (specified in initParams.pins) 37 | * ic595 latch | Brown Stripe | (specified in initParams.pins) 38 | * D/A Input | Brown | (specified in initParams.pins) 39 | * 40 | * For more information about the board design, see: [TODO] 41 | * 42 | * @class IOBoard 43 | * @constructor 44 | * @param initParams {Object} Probe initialization parameters 45 | * @param [initParams.sleepMs=100] {Integer} Milliseconds to sleep after polling 46 | * all inputs. 47 | * @param initParams.pins {Object} BeagleBone I/O pin IDs (ex: P9_22) 48 | * @param initParams.pins.data {String} Pin number for ic595 data 49 | * @param initParams.pins.clock {String} Pin number for ic595 clock 50 | * @param initParams.pins.latch {String} Pin number for ic595 latch 51 | * @param initParams.pins.input {String} Pin number for digital or analog input. 52 | * If this is one of the analog input pins then analog values 53 | * between 0 and 1 are provided. Otherwise 0 or 1 are provided. 54 | * @param initParams.inputs {Object Array} Array defining all input positions. 55 | * @param initParams.inputs.n.name {String} Name of the probe variable to use 56 | * @param [initParams.inputs.n.description] {String} Human description of the input 57 | * @param initParams.outputs {Object Array} Array defining all output positions. 58 | * @param initParams.outputs.n.name {String} Name of the probe variable to use 59 | * @param [initParams.outputs.n.description] {String} Human description of the input 60 | * @param [initParams.outputs.n.initialValue=0] {Integer} Initial output value (0 or 1) 61 | */ 62 | var IOBoard = Probe.extend({ 63 | 64 | probeClass: 'IOBoard', 65 | 66 | // Called by Backbone.Model on object construction 67 | initialize: function(options){ 68 | var t = this; 69 | 70 | // Assume callback responsibility 71 | options.asyncInit = true; 72 | var callback = options.callback; 73 | 74 | // Assign instance data 75 | t.pins = options.pins; 76 | t.sleepMs = (typeof options.sleepMs === 'undefined') ? 100 : options.sleepMs; 77 | t.inputs = options.inputs; 78 | t.numInputs = t.inputs.length; 79 | t.outputs = options.outputs; 80 | t.numOutputs = t.outputs.length; 81 | t.num595chips = 1 + Math.ceil(t.numOutputs / 8); 82 | t.ic595 = null; 83 | t.isAnalogInput = ANALOG_INPUT_PINS.indexOf(t.pins.input) >= 0; 84 | t.readFn = t.isAnalogInput ? Bonescript.analogRead : Bonescript.digitalRead; 85 | t.timer = null; // Timer before next heartbeat 86 | t.cyanide = false; 87 | t.validOutputNames = []; 88 | t.ic595Array = []; // One element per 595 chip 89 | t.first595 = [0]; // First 595 chip (controller) 90 | t.currentInput = 0; 91 | t.currentOutputLatch = 0; 92 | t.outputQueued = false; 93 | t.heartbeatFn = function(){t.nextHeartbeat();}; 94 | 95 | // Build the named data model elements 96 | t.inputs.forEach(function(input){ 97 | t.set(input.name, 0, {silent:true}); 98 | }); 99 | t.outputs.forEach(function(output){ 100 | t.validOutputNames.push(output.name); 101 | t.set(output.name, output.initialValue ? 1 : 0, {silent:true}); 102 | }); 103 | 104 | // Initialize the 959 array with zeros 105 | for (var i = 0; i < t.num595chips; i++) { 106 | t.ic595Array.push(0); 107 | } 108 | 109 | // Initialize the input pin 110 | var modes = [{name: t.pins.input, direction: Bonescript.INPUT}]; 111 | BBUtils.initGPIO(modes, function(error) { 112 | if (error) { 113 | logger.error('GPIO Init', error); 114 | return callback(error); 115 | } 116 | 117 | // Initialize the 595 ICs. One of the zeros is for the 118 | // enable line in the secondary 959s, keeping all outputs disabled. 119 | console.log('initializing 595', t.ic595Array); 120 | t.ic595 = new IC595({pins:t.pins, values:t.ic595Array}, function(error) { 121 | console.log('595 initialized'); 122 | if (error) { 123 | logger.error('595init', error); 124 | return callback(error); 125 | } 126 | 127 | // Queue the current outputs to be sent 128 | t.queueOutputs(); 129 | console.log('Outputs queued'); 130 | 131 | // Perform the first full heartbeat, and callback from initialize 132 | // once all inputs have been read. 133 | t.nextHeartbeat(callback); 134 | }); 135 | }); 136 | }, 137 | 138 | // Shut down the probe 139 | release: function() { 140 | var t = this; 141 | if (t.timer) { 142 | clearTimeout(t.timer); 143 | t.timer = null; 144 | } 145 | else { 146 | t.cyanide = true; 147 | } 148 | }, 149 | 150 | // This changes the output pin states, and sets up for sending those 151 | // out during the next heartbeat interval. 152 | queueOutputs: function() { 153 | var t = this; 154 | 155 | // Delay queueing outputs until the current batch is set and latched. 156 | if (t.currentOutputLatch === 1) { 157 | setTimeout(function(){ 158 | t.queueOutputs(); 159 | }, 10); 160 | } 161 | 162 | // Set the 595 values to the full array including outputs 163 | var current595Values = t.ic595.values; 164 | t.ic595.values = t.ic595Array; 165 | 166 | // Set each output value into the array 167 | for (var i = 0; i < t.outputs.length; i++) { 168 | var value = t.get(t.outputs[i].name); 169 | t.ic595.set(i + 8, value); 170 | } 171 | 172 | // Reset the 595 values 173 | t.ic595.values = current595Values; 174 | 175 | // Queue outputs for sending on the next rotation 176 | t.outputQueued = true; 177 | }, 178 | 179 | // Heartbeat processing. One heartbeat reads each input, and sends output 180 | // if queued. At the end of a heartbeat, it sleeps for the configured 181 | // interval, and calls the heartbeat again. 182 | nextHeartbeat: function(callback) { 183 | var t = this, 184 | rotateInput = null, 185 | readInput = null, 186 | startStamp = Date.now(); 187 | 188 | // This is a safety valve, and shouldn't happen 189 | if (t.currentInput !== 0) { 190 | logger.error('nextHeartbeat', 'BUG: nextHeartbeat called during an existing heartbeat'); 191 | return; 192 | } 193 | 194 | // Reset the timer 195 | if (t.timer) { 196 | clearTimeout(t.timer); 197 | t.timer = null; 198 | } 199 | 200 | // Rotate the input switch to the next position 201 | rotateInput = function() { 202 | 203 | // Rotate the switch back to zero at the end 204 | if (++t.currentInput === t.numInputs) { 205 | t.currentInput = 0; 206 | } 207 | 208 | // Output to all 595s or just the first one 209 | if (t.outputQueued) { 210 | t.ic595.values = t.ic595Array; 211 | } else { 212 | t.ic595.values = t.first595; 213 | } 214 | 215 | // Set up the first 595 - controller 216 | // 0: InputData0 217 | // 1: InputData1 218 | // 2: InputData2 219 | // 3: InputData3 220 | // 4: not used 221 | // 5: not used 222 | // 6: OutputEnable - (always on after first output) 223 | // 7: OutputLatch - High on output now, low on next cycle 224 | t.ic595.values[0] = t.currentInput; // This sets 0-3 to the input switch location 225 | t.ic595.set(6, 1); 226 | t.currentOutputLatch = t.outputQueued ? 1 : 0; 227 | t.ic595.set(7, t.currentOutputLatch); 228 | 229 | // Reset the output queue 230 | if (t.outputQueued) { 231 | logger.info('rotateInput', 'Sending outputs along with input rotation'); 232 | t.outputQueued = false; 233 | } 234 | 235 | // Now shift everything out 236 | t.ic595.shiftOut(function(err) { 237 | 238 | // We're done with the rotation if we're back around to zero and we 239 | // don't have to do another round to reset the output latch. 240 | if (t.currentInput === 0 && t.currentOutputLatch === 0) { 241 | logger.info('heartbeat', 'complete in ' + (Date.now() - startStamp) + ' ms.'); 242 | 243 | // Set up for the next heartbeat, or stop the heart 244 | if (!t.cyanide) { 245 | t.timer = setTimeout(t.heartbeatFn, t.sleepMs); 246 | } 247 | 248 | // We're done with the rotation 249 | if (callback) { 250 | callback(); 251 | } 252 | return; 253 | } 254 | 255 | // Now read the newly rotated position 256 | readInput(); 257 | }); 258 | } 259 | 260 | // Read the current input position, and set it into the model if changed. 261 | // The set up for the next input. 262 | readInput = function() { 263 | t.readFn(t.pins.input, function(x) { 264 | if (x.err) { 265 | logger.error('readInput', {msg:'Error reading input', err:x.err}); 266 | } 267 | else { 268 | // Set the input value if it's different. This triggers a change immediately. 269 | var attrName = t.inputs[t.currentInput].name; 270 | if (t.get(attrName) !== x.value) { 271 | t.set(attrName, x.value); 272 | } 273 | } 274 | 275 | // Get the next value 276 | rotateInput(); 277 | }); 278 | } 279 | 280 | // Start by reading the current position (which should be 0) 281 | readInput(); 282 | }, 283 | 284 | /** 285 | * Allow outputs to be set by monitors 286 | * 287 | * @method setOutputs_control 288 | * @param outputs {Object} Name/value outputs to set into the probe. Only names 289 | * defined as outputs can be set by this control, and 290 | * only 0 or 1 are valid values. 291 | * @param callback {function(err)} Called when done or error 292 | */ 293 | setOutputs_control: function(outputs, callback) { 294 | var t = this; 295 | callback = callback || function(){}; 296 | 297 | // Validate the param names and values 298 | var value = null; 299 | for (var paramName in outputs) { 300 | if (t.validOutputsNames.indexOf(paramName) < 0) { 301 | var err = {msg: 'Invalid output param: "' + paramName + '"'}; 302 | logger.error('setOutputs', err); 303 | return callback(err); 304 | } 305 | value = outputs[paramName]; 306 | if (value !== 0 && value !== 1) { 307 | var err = {msg: 'Invalid output value (must be 0 or 1)', value: value}; 308 | logger.error('setOutputs', err); 309 | return callback(err); 310 | } 311 | } 312 | 313 | // Now set the output values (this updates monitors) 314 | t.set(outputs); 315 | 316 | // Queue the outputs for the next heartbeat 317 | t.queueOutputs(); 318 | 319 | // Perform next heartbeat now if we're in waiting 320 | if (t.timer) { 321 | t.nextHeartbeat(); 322 | } 323 | 324 | // Success 325 | return callback(); 326 | } 327 | 328 | }); 329 | -------------------------------------------------------------------------------- /lib/probe/BeagleBone.js: -------------------------------------------------------------------------------- 1 | // BeagleBone.js (c) 2013-2014 Loren West 2 | // May be freely distributed under the MIT license. 3 | // For further details and documentation: 4 | // http://lorenwest.github.com/beaglebone-monitor 5 | 6 | var Monitor = require('monitor'), 7 | logger = Monitor.getLogger('BeagleBone'), 8 | Probe = Monitor.Probe, 9 | Config = Monitor.Config, 10 | Bonescript = require('bonescript'), 11 | bonePins = Bonescript.bone.pins, 12 | logger = Monitor.getLogger('BeagleBone'); 13 | 14 | // Require Bonescript 0.2.4 or above 15 | var bsVersion = Bonescript.getPlatform().bonescript; 16 | var bsVersionParts = bsVersion.split('.'); 17 | if (bsVersionParts[0] == 0 && (bsVersionParts[1] < 2 || (bsVersionParts[1] == 2 && bsVersionParts[2] < 4))) { 18 | console.error('Bonescript version ' + bsVersion); 19 | console.error('Must be version 0.2.4 or greater for stability.'); 20 | process.exit(1); 21 | } 22 | 23 | /** 24 | * Probe exposure of a BeagleBone, for remote monitoring & control 25 | * 26 | * This is designed to be run as a singleton on the beaglebone. It offers a 27 | * single point of interaction with the microcontroller. 28 | * 29 | * It allows you to define pin names, and interact with the beaglebone using your 30 | * own pin names, and establish polling and real-time monitoring for input pins. 31 | * 32 | * The data model contains an element for each mapped pin (by name), and an 33 | * element called pins, containing a hash of pin name to everything known about 34 | * that pin. 35 | * 36 | * @class BeagleBone 37 | * @constructor 38 | */ 39 | var BeagleBone = Probe.extend({ 40 | 41 | probeClass: 'BeagleBone', 42 | writableAttributes: '*', 43 | 44 | /** 45 | * Initialize the probe with known pin mappings 46 | * 47 | * You can define pins as probe initialization parameters, or if the probe 48 | * is already running, you can add pin definitions using the 'definePins' 49 | * probe control. 50 | * 51 | * @constructor 52 | * 53 | * @param pins {Array of Object} Initial I/O pin definitions 54 | * @param pins.n.id {String} The beaglebone name of the pin ('P9_22') 55 | * @param [pins.n.name] {String} The logical name to assign the pin 56 | * @param [pins.n.direction='in'] {String} Pin direction ('in' or 'out') 57 | * @param [pins.n.value] {Mixed} Initial value to set the pin to 58 | * @param [pins.mux=7] - (GPIO out) One of 'pullup', 'pulldown', or 'disabled' 59 | * @param [pins.pull='pullup'] - (GPIO out) One of 'pullup', 'pulldown', or 'disabled' 60 | * @param [pins.slew='fast'] - (GPIO out) One of 'fast' or 'slow' 61 | * @param [pins.frequency=2000] - PWM frequency for digital output pins 62 | * @param [pins.n.precision=3] {Number} Number of digits to retain past the 63 | * decimal point (rounded) for analog input pins. 64 | * Dry contacts use 0 (for 0/1) 65 | * @param [pins.n.pollMs=1000] {Number} Number of milliseconds to poll for input values 66 | */ 67 | initialize: function(params, options) { 68 | var t = this, 69 | pins = t.get('pins'); 70 | 71 | // Take over callback control 72 | options.asyncInit = true; 73 | 74 | // Determine if we're running on a beaglebone or in emulation mode 75 | Bonescript.getPlatform(function(platform) { 76 | if (!platform.serialNumber) { 77 | logger.info('initialize', 'No beaglebone detected. Running in emulation mode.'); 78 | t.set('emulationMode', true); 79 | } 80 | 81 | // The pin map by ID keys on BeagleBone pin name 82 | // key=>beaglebone pin name 'P9_22' value=>Pin object 83 | t.pinMapById = {}; 84 | 85 | // The pin map by name keys on the defined name for the pin 86 | // and is exposed as 'pins' in the data model. 87 | // key=>Pin name (as set by definePins), value=>Pin object 88 | t.pinMapByName = {}; 89 | t.pinMapString = ''; 90 | 91 | // key=>ms delay, value=>{interval:interval, readPins:[array of pins to read]} 92 | t.timerMap = {}; 93 | 94 | // Configure the pins 95 | logger.info('init.pins', 'Configuring initial pins', pins); 96 | t.definePins_control(pins, options.callback); 97 | }); 98 | }, 99 | 100 | // This updates the data model in a single change. 101 | // @param updates {Object} Map of pin names to values 102 | updateModel: function(updates) { 103 | var t = this; 104 | 105 | // Update the whole pin map if necessary 106 | var pinMapString = JSON.stringify(t.pinMapByName); 107 | if (t.pinMapString !== pinMapString) { 108 | t.pinMapString = pinMapString; 109 | updates.pins = JSON.parse(JSON.stringify(t.pinMapByName)); 110 | } 111 | 112 | // Update the data model 113 | t.set(updates); 114 | }, 115 | 116 | /** 117 | * Define controller pin mappings 118 | * 119 | * Pin mappings initialize the beaglebone I/O pins and map them to your 120 | * own names. 121 | * 122 | * @method definePins_control - Remote pin mapping 123 | * @param pins {Array of Object} Initial I/O pin definitions 124 | * @param pins.n.id {String} The beaglebone name of the pin ('P9_22') 125 | * @param [pins.n.name] {String} The logical name to assign the pin 126 | * @param [pins.n.direction='in'] {String} Pin direction ('in' or 'out') 127 | * @param [pins.n.value] {Mixed} Initial value to set the pin to 128 | * @param [pins.mux=7] - (GPIO out) One of 'pullup', 'pulldown', or 'disabled' 129 | * @param [pins.pull='pullup'] - (GPIO out) One of 'pullup', 'pulldown', or 'disabled' 130 | * @param [pins.slew='fast'] - (GPIO out) One of 'fast' or 'slow' 131 | * @param [pins.frequency=2000] - PWM frequency for digital output pins 132 | * @param [pins.n.precision=3] {Number} Number of digits to retain past the 133 | * decimal point (rounded) for analog input pins. 134 | * Dry contacts use 0 (for 0/1) 135 | * @param [pins.n.pollMs=1000] {Number} Number of milliseconds to poll for input values 136 | * @param callback {function(error)} - Called when done 137 | */ 138 | definePins_control: function(pins, callback) { 139 | var t = this, 140 | pinsToSetMode = [], // full pin definition 141 | pinsToRead = [], // pin names 142 | pinsToWrite = {}; // Map of pin name->value 143 | 144 | // Nothing to do 145 | if (!pins.length) { 146 | callback(null); 147 | } 148 | 149 | // Perform validation before setting the pins 150 | pins.forEach(function(pin) { 151 | 152 | // Is this a known pin? 153 | if (!bonePins[pin.id]) { 154 | return callback({code: 'UNKNOWN_PIN', msg: 'BeagleBone pin name not found: ' + pin.id, pin: pin}); 155 | } 156 | pin.bonePin = bonePins[pin.id]; 157 | 158 | }); 159 | 160 | // Define each pin 161 | pins.forEach(function(pin) { 162 | 163 | // Default pin values 164 | pin.name = pin.name || pin.id; 165 | pin.direction = pin.direction || 'in'; 166 | if (pin.bonePin.mux) { 167 | pin.mux = pin.mux === 'undefined' ? 7 : pin.mux; 168 | } 169 | 170 | // Add the pin definition to the maps 171 | t.pinMapById[pin.id] = pin; 172 | t.pinMapByName[pin.name] = pin; 173 | 174 | // Process a GPIO pin 175 | if (pin.bonePin.gpio) { 176 | if (pin.direction === 'in') { 177 | pin.precision = 0; 178 | pinsToRead.push(pin.name); 179 | } 180 | else { 181 | if (typeof pin.value !== 'undefined') { 182 | pinsToWrite[pin.name] = pin.value; 183 | } 184 | } 185 | pinsToSetMode.push(pin); 186 | } 187 | 188 | // Process an analog input pin 189 | else if (typeof pin.bonePin.ain !== 'undefined') { 190 | if (pin.direction !== 'in') { 191 | return callback({code:'PIN_ERROR', msg: 'Cannot do PWM on an analog input pin: ' + pin.name, pin: pin}); 192 | } 193 | if (typeof pin.precision === 'undefined') { 194 | pin.precision = 3; 195 | } 196 | pinsToRead.push(pin.name); 197 | } 198 | 199 | }); 200 | 201 | // Setup the polling timers 202 | var setTimers = function() { 203 | pins.forEach(function(pin) { 204 | var pollMs = pin.pollMs; 205 | if (pollMs >= 0 && pin.direction === 'in') { 206 | 207 | // Define the timerMap for this polling interval 208 | // TimerMap: key=>ms delay, value=>{interval:interval, readPins:[array of pins to read]} 209 | if (!t.timerMap[pollMs]) { 210 | t.timerMap[pollMs] = { 211 | interval: null, 212 | readPins:[] 213 | } 214 | t.timerMap[pollMs].interval = setInterval(function() { 215 | t.read_control(t.timerMap[pollMs].readPins, function(error) { 216 | if (error) { 217 | logger.error('pollMs', error); 218 | } 219 | }); 220 | }, pollMs); 221 | } 222 | 223 | // Add this pin to the timer map 224 | t.timerMap[pollMs].readPins.push(pin.name); 225 | } 226 | }); 227 | } 228 | 229 | // Set pin modes, write outputs, then read inputs 230 | t.setPinModes(pinsToSetMode, function(error) { 231 | if (error) { 232 | return callback(error); 233 | } 234 | t.write_control(pinsToWrite, function(error) { 235 | if (error) { 236 | return callback(error); 237 | } 238 | t.read_control(pinsToRead, function(error) { 239 | if (error) { 240 | return callback(error); 241 | } 242 | setTimers(); 243 | return callback(null); 244 | }); 245 | }); 246 | }); 247 | }, 248 | 249 | /** 250 | * Read a bunch of digital or analog pins 251 | * 252 | * @method read_control 253 | * @param pinNames {Array of String} Array of defined pin names to read 254 | * @param callback {function(error, valueMap)} - A map of pin name to pin values 255 | */ 256 | read_control: function(pinNames, callback) { 257 | var t = this, 258 | didError = false, 259 | valueMap = {}; 260 | 261 | // Convert to an array 262 | pinNames = Array.isArray(pinNames) ? pinNames : [pinNames]; 263 | var numLeft = pinNames.length; 264 | if (pinNames.length === 0) { 265 | return callback(null,{}); 266 | } 267 | 268 | // Validate the input 269 | pinNames.forEach(function(pinName) { 270 | var pin = t.pinMapByName[pinName]; 271 | if (!pin) { 272 | return callback({code:'NO_PIN', msg:'No pin defined with name: ' + pinName}); 273 | } 274 | if (pin.direction !== 'in') { 275 | return callback({code:'BAD_PIN', msg:'This isnt an input pin: ' + pinName}); 276 | } 277 | if (!pin.bonePin.gpio && typeof pin.bonePin.ain === 'undefined') { 278 | return callback({code:'BAD_PIN_TYPE', msg:'This isnt a digital or analog input pin: ' + pinName}); 279 | } 280 | }); 281 | 282 | // Called when done 283 | var numLeft = pinNames.length; 284 | var whenDone = function(error) { 285 | if (didError) { 286 | return; 287 | } 288 | if (error) { 289 | didError = true; 290 | t.updateModel(valueMap); 291 | return callback(error); 292 | } 293 | if (--numLeft === 0) { 294 | t.updateModel(valueMap); 295 | return callback(null, valueMap); 296 | } 297 | } 298 | 299 | // Perform the read on each pin 300 | pinNames.forEach(function(pinName) { 301 | var pin = t.pinMapByName[pinName], 302 | readFn = typeof pin.bonePin.ain === 'undefined' ? 'digitalRead' : 'analogRead'; 303 | if (t.get('emulationMode')) { 304 | logger.trace('read_control', 'Emulating ' + readFn + '(' + pin.id + ') for ' + pin.name); 305 | return whenDone(); 306 | } 307 | else { 308 | Bonescript[readFn](pin.id, function(x) { 309 | var error = x.err; 310 | var value = x.value; 311 | if (!error) { 312 | value = +value.toFixed(pin.precision); 313 | valueMap[pinName] = value; 314 | } 315 | whenDone(error); 316 | }); 317 | } 318 | }); 319 | }, 320 | 321 | /** 322 | * Write a bunch of pins, calling the callback when done 323 | * 324 | * @method write_control 325 | * @param pins {Object} Map of pins to write, name=pinName, value=value 326 | * @param callback {function(error)} - Called when complete 327 | */ 328 | write_control: function(pins, callback) { 329 | var t = this, 330 | didError = false, 331 | allPins = []; 332 | 333 | // Validate the input 334 | for (var pinName in pins) { 335 | var pin = t.pinMapByName[pinName]; 336 | if (!pin) { 337 | continue; 338 | } 339 | if (pin.direction !== 'out') { 340 | return callback({code:'BAD_PIN', msg:'This isnt an output pin: ' + pinName}); 341 | } 342 | allPins.push(pinName); 343 | } 344 | if (!allPins.length) { 345 | t.updateModel(pins); 346 | return callback(null); 347 | } 348 | 349 | // Called when done 350 | var numLeft = allPins.length; 351 | var whenDone = function(error) { 352 | if (didError) { 353 | return; 354 | } 355 | if (error) { 356 | didError = true; 357 | return callback(error); 358 | } 359 | if (--numLeft === 0) { 360 | t.updateModel(pins); 361 | return callback(null); 362 | } 363 | } 364 | 365 | // Perform the write on each pin 366 | allPins.forEach(function(pinName) { 367 | var pin = t.pinMapByName[pinName], 368 | value = pins[pinName]; 369 | 370 | // Is this an analog (pwm) write? 371 | if (pin.bonePin.pwm && pin.bonePin.pwm.muxmode === pin.mux) { 372 | 373 | if (t.get('emulationMode')) { 374 | logger.trace('write_control', 'Emulating analogWrite(' + pin.id + ',' + value + ') for ' + pin.name); 375 | return whenDone(); 376 | } 377 | else { 378 | Bonescript.analogWrite(pin.id, value, pin.frequency, function(x) { 379 | whenDone(x && x.err); 380 | }); 381 | } 382 | } 383 | 384 | // Digital write 385 | else { 386 | if (t.get('emulationMode')) { 387 | logger.trace('write_control', 'Emulating digitalWrite(' + pin.id + ',' + value + ') for ' + pin.name); 388 | return whenDone(); 389 | } 390 | else { 391 | Bonescript.digitalWrite(pin.id, value, function(x) { 392 | whenDone(x && x.err); 393 | }); 394 | } 395 | } 396 | }); 397 | }, 398 | 399 | /** 400 | * Remotely set a probe attribute. 401 | * 402 | * This overrides Probe.set_control for settable monitor attributes. It allows 403 | * setting pin values by using the remote model.set() method. 404 | * 405 | * @method set_control 406 | * @param attrs {Object} Name/Value attributes to set. All must be writable. 407 | * @param callback {Function(error)} Called when the attributes are set or error 408 | */ 409 | set_control: function(attrs, callback) { 410 | var t = this; 411 | t.write_control(attrs, callback); 412 | }, 413 | 414 | /** 415 | * Set pin modes for a group of pins 416 | * 417 | * @method setPinModes 418 | * @param pins {Object array} An array of pin modes to set 419 | * @param pins.n.id {String} The beaglebone pin name (P9_22) 420 | * @param pins.n.direction - One of b.INPUT or b.OUTPUT 421 | * @param [pins.n.mux=7] - Pin mux number (7 for gpio) 422 | * @param [pins.n.pull='pullup'] - One of 'pullup', 'pulldown', or 'disabled' 423 | * @param [pins.slew='fast'] - One of 'fast' or 'slow' 424 | * @param callback {function(error)} - Callback when complete 425 | */ 426 | setPinModes: function(pins, callback) { 427 | var t = this; 428 | 429 | // Make an array, and default callback 430 | pins = Array.isArray(pins) ? pins : [pins]; 431 | if (pins.length === 0) { 432 | return callback(null); 433 | } 434 | 435 | // Make an array, and default callback 436 | // Function for each pin 437 | var setPin = function(currentPin, cb) { 438 | var pin = pins[currentPin], 439 | mux = typeof pin.mux === 'undefined' ? 7 : pin.mux, 440 | pull = pin.pull ? pin.pull : 'pullup', 441 | slew = pin.slew ? pin.slew : 'fast'; 442 | 443 | // Set the mode 444 | if (t.get('emulationMode')) { 445 | logger.trace('setPinModes', 'Emulating pinMode(' + pin.id +',' + mux + ') for ' + pin.name); 446 | return whenDone(); 447 | } 448 | else { 449 | Bonescript.pinMode(pin.id, pin.direction, mux, pull, slew, function(err) { 450 | if (err && err.err) { 451 | return cb({err: err, msg: 'Error setting the pin mode for: ' + pin.id}); 452 | } 453 | return cb(null); 454 | }); 455 | } 456 | }; 457 | 458 | // Called when done with each pin 459 | var didError = false; 460 | var numLeft = pins.length; 461 | var whenDone = function(error) { 462 | if (didError) { 463 | return; 464 | } 465 | if (error) { 466 | didError = true; 467 | return callback(error); 468 | } 469 | if (--numLeft === 0) { 470 | callback(); 471 | } 472 | } 473 | 474 | // Set each pin in parallel 475 | for (var i = 0; i < pins.length; i++) { 476 | setPin(i, whenDone); 477 | } 478 | }, 479 | 480 | // Release resources held by the probe 481 | release: function() { 482 | var t = this; 483 | 484 | // Shut down all timers 485 | for (var i in t.timerMap) { 486 | var timer = t.timerMap[i]; 487 | clearInterval(timer.interval); 488 | } 489 | t.timerMap = {}; 490 | } 491 | 492 | }); 493 | -------------------------------------------------------------------------------- /pins.json: -------------------------------------------------------------------------------- 1 | { USR0: 2 | { name: 'USR0', 3 | gpio: 53, 4 | led: 'usr0', 5 | mux: 'gpmc_a5', 6 | key: 'USR0', 7 | muxRegOffset: '0x054', 8 | options: 9 | [ 'gpmc_a5', 10 | 'gmii2_txd0', 11 | 'rgmii2_td0', 12 | 'rmii2_txd0', 13 | 'gpmc_a21', 14 | 'pr1_mii1_rxd3', 15 | 'eqep1b_in', 16 | 'gpio1_21' ] }, 17 | USR1: 18 | { name: 'USR1', 19 | gpio: 54, 20 | led: 'usr1', 21 | mux: 'gpmc_a6', 22 | key: 'USR1', 23 | muxRegOffset: '0x058', 24 | options: 25 | [ 'gpmc_a6', 26 | 'gmii2_txclk', 27 | 'rgmii2_tclk', 28 | 'mmc2_dat4', 29 | 'gpmc_a22', 30 | 'pr1_mii1_rxd2', 31 | 'eqep1_index', 32 | 'gpio1_22' ] }, 33 | USR2: 34 | { name: 'USR2', 35 | gpio: 55, 36 | led: 'usr2', 37 | mux: 'gpmc_a7', 38 | key: 'USR2', 39 | muxRegOffset: '0x05c', 40 | options: 41 | [ 'gpmc_a7', 42 | 'gmii2_rxclk', 43 | 'rgmii2_rclk', 44 | 'mmc2_dat5', 45 | 'gpmc_a23', 46 | 'pr1_mii1_rxd1', 47 | 'eqep1_strobe', 48 | 'gpio1_23' ] }, 49 | USR3: 50 | { name: 'USR3', 51 | gpio: 56, 52 | led: 'usr3', 53 | mux: 'gpmc_a8', 54 | key: 'USR3', 55 | muxRegOffset: '0x060', 56 | options: 57 | [ 'gpmc_a8', 58 | 'gmii2_rxd3', 59 | 'rgmii2_rd3', 60 | 'mmc2_dat6', 61 | 'gpmc_a24', 62 | 'pr1_mii1_rxd0', 63 | 'mcasp0_aclkx', 64 | 'gpio1_24' ] }, 65 | P8_1: { name: 'DGND', key: 'P8_1' }, 66 | P8_2: { name: 'DGND', key: 'P8_2' }, 67 | P8_3: 68 | { name: 'GPIO1_6', 69 | gpio: 38, 70 | mux: 'gpmc_ad6', 71 | eeprom: 26, 72 | key: 'P8_3', 73 | muxRegOffset: '0x018', 74 | options: 75 | [ 'gpmc_ad6', 76 | 'mmc1_dat6', 77 | 'NA', 78 | 'NA', 79 | 'NA', 80 | 'NA', 81 | 'NA', 82 | 'gpio1_6' ] }, 83 | P8_4: 84 | { name: 'GPIO1_7', 85 | gpio: 39, 86 | mux: 'gpmc_ad7', 87 | eeprom: 27, 88 | key: 'P8_4', 89 | muxRegOffset: '0x01c', 90 | options: 91 | [ 'gpmc_ad7', 92 | 'mmc1_dat7', 93 | 'NA', 94 | 'NA', 95 | 'NA', 96 | 'NA', 97 | 'NA', 98 | 'gpio1_7' ] }, 99 | P8_5: 100 | { name: 'GPIO1_2', 101 | gpio: 34, 102 | mux: 'gpmc_ad2', 103 | eeprom: 22, 104 | key: 'P8_5', 105 | muxRegOffset: '0x008', 106 | options: 107 | [ 'gpmc_ad2', 108 | 'mmc1_dat2', 109 | 'NA', 110 | 'NA', 111 | 'NA', 112 | 'NA', 113 | 'NA', 114 | 'gpio1_2' ] }, 115 | P8_6: 116 | { name: 'GPIO1_3', 117 | gpio: 35, 118 | mux: 'gpmc_ad3', 119 | eeprom: 23, 120 | key: 'P8_6', 121 | muxRegOffset: '0x00c', 122 | options: 123 | [ 'gpmc_ad3', 124 | 'mmc1_dat3', 125 | 'NA', 126 | 'NA', 127 | 'NA', 128 | 'NA', 129 | 'NA', 130 | 'gpio1_3' ] }, 131 | P8_7: 132 | { name: 'TIMER4', 133 | gpio: 66, 134 | mux: 'gpmc_advn_ale', 135 | eeprom: 41, 136 | key: 'P8_7', 137 | muxRegOffset: '0x090', 138 | options: 139 | [ 'gpmc_advn_ale', 140 | 'NA', 141 | 'NA', 142 | 'NA', 143 | 'NA', 144 | 'NA', 145 | 'NA', 146 | 'mmc1_sdcd' ] }, 147 | P8_8: 148 | { name: 'TIMER7', 149 | gpio: 67, 150 | mux: 'gpmc_oen_ren', 151 | eeprom: 44, 152 | key: 'P8_8', 153 | muxRegOffset: '0x094', 154 | options: 155 | [ 'gpmc_oen_ren', 156 | 'NA', 157 | 'NA', 158 | 'NA', 159 | 'NA', 160 | 'NA', 161 | 'NA', 162 | 'gpio2_3' ] }, 163 | P8_9: 164 | { name: 'TIMER5', 165 | gpio: 69, 166 | mux: 'gpmc_ben0_cle', 167 | eeprom: 42, 168 | key: 'P8_9', 169 | muxRegOffset: '0x09c', 170 | options: 171 | [ 'gpmc_ben0_cle', 172 | 'NA', 173 | 'NA', 174 | 'NA', 175 | 'NA', 176 | 'NA', 177 | 'NA', 178 | 'gpio2_5' ] }, 179 | P8_10: 180 | { name: 'TIMER6', 181 | gpio: 68, 182 | mux: 'gpmc_wen', 183 | eeprom: 43, 184 | key: 'P8_10', 185 | muxRegOffset: '0x098', 186 | options: 187 | [ 'gpmc_wen', 188 | 'NA', 189 | 'NA', 190 | 'NA', 191 | 'NA', 192 | 'NA', 193 | 'NA', 194 | 'gpio2_4' ] }, 195 | P8_11: 196 | { name: 'GPIO1_13', 197 | gpio: 45, 198 | mux: 'gpmc_ad13', 199 | eeprom: 29, 200 | key: 'P8_11', 201 | muxRegOffset: '0x034', 202 | options: 203 | [ 'gpmc_ad13', 204 | 'lcd_data18', 205 | 'mmc1_dat5', 206 | 'mmc2_dat1', 207 | 'eqep2B_in', 208 | 'pr1_mii0_txd', 209 | 'pr1_pru0_pru_r30_15', 210 | 'gpio1_13' ] }, 211 | P8_12: 212 | { name: 'GPIO1_12', 213 | gpio: 44, 214 | mux: 'gpmc_ad12', 215 | eeprom: 28, 216 | key: 'P8_12', 217 | muxRegOffset: '0x030', 218 | options: 219 | [ 'gpmc_ad12', 220 | 'lcd_data19', 221 | 'mmc1_dat4', 222 | 'mmc2_dat0', 223 | 'eqep2a_in', 224 | 'pr1_mii0_txd2', 225 | 'pr1_pru0_pru_r30_14', 226 | 'gpio1_12' ] }, 227 | P8_13: 228 | { name: 'EHRPWM2B', 229 | gpio: 23, 230 | mux: 'gpmc_ad9', 231 | eeprom: 15, 232 | pwm: 233 | { module: 'ehrpwm2', 234 | muxmode: 4, 235 | path: 'ehrpwm.2:1', 236 | name: 'EHRPWM2B' }, 237 | key: 'P8_13', 238 | muxRegOffset: '0x024', 239 | options: 240 | [ 'gpmc_ad9', 241 | 'lcd_data22', 242 | 'mmc1_dat1', 243 | 'mmc2_dat5', 244 | 'ehrpwm2B', 245 | 'pr1_mii0_col', 246 | 'NA', 247 | 'gpio0_23' ] }, 248 | P8_14: 249 | { name: 'GPIO0_26', 250 | gpio: 26, 251 | mux: 'gpmc_ad10', 252 | eeprom: 16, 253 | key: 'P8_14', 254 | muxRegOffset: '0x028', 255 | options: 256 | [ 'gpmc_ad10', 257 | 'lcd_data21', 258 | 'mmc1_dat2', 259 | 'mmc2_dat6', 260 | 'ehrpwm2_tripzone_input', 261 | 'pr1_mii0_txen', 262 | 'NA', 263 | 'gpio0_26' ] }, 264 | P8_15: 265 | { name: 'GPIO1_15', 266 | gpio: 47, 267 | mux: 'gpmc_ad15', 268 | eeprom: 31, 269 | key: 'P8_15', 270 | muxRegOffset: '0x03c', 271 | options: 272 | [ 'gpmc_ad15', 273 | 'lcd_data16', 274 | 'mmc1_dat7', 275 | 'mmc2_dat3', 276 | 'eqep2_strobe', 277 | 'pr1_ecap0_ecap_capin_apwm_o', 278 | 'pr1_pru0_pru_r31_15', 279 | 'gpio1_15' ] }, 280 | P8_16: 281 | { name: 'GPIO1_14', 282 | gpio: 46, 283 | mux: 'gpmc_ad14', 284 | eeprom: 30, 285 | key: 'P8_16', 286 | muxRegOffset: '0x038', 287 | options: 288 | [ 'gpmc_ad14', 289 | 'lcd_data17', 290 | 'mmc1_dat6', 291 | 'mmc2_dat2', 292 | 'eqep2_index', 293 | 'pr1_mii0_txd0', 294 | 'pr1_pru0_pru_r31_14', 295 | 'gpio1_14' ] }, 296 | P8_17: 297 | { name: 'GPIO0_27', 298 | gpio: 27, 299 | mux: 'gpmc_ad11', 300 | eeprom: 17, 301 | key: 'P8_17', 302 | muxRegOffset: '0x02c', 303 | options: 304 | [ 'gpmc_ad11', 305 | 'lcd_data20', 306 | 'mmc1_dat3', 307 | 'mmc2_dat7', 308 | 'ehrpwm0_synco', 309 | 'pr1_mii0_txd3', 310 | 'NA', 311 | 'gpio0_27' ] }, 312 | P8_18: 313 | { name: 'GPIO2_1', 314 | gpio: 65, 315 | mux: 'gpmc_clk', 316 | eeprom: 40, 317 | key: 'P8_18', 318 | muxRegOffset: '0x08c', 319 | options: 320 | [ 'gpmc_clk', 321 | 'lcd_memory_clk_mux', 322 | 'NA', 323 | 'mmc2_clk', 324 | 'NA', 325 | 'NA', 326 | 'mcasp0_fsr', 327 | 'gpio2_1' ] }, 328 | P8_19: 329 | { name: 'EHRPWM2A', 330 | gpio: 22, 331 | mux: 'gpmc_ad8', 332 | eeprom: 14, 333 | pwm: 334 | { module: 'ehrpwm2', 335 | muxmode: 4, 336 | path: 'ehrpwm.2:0', 337 | name: 'EHRPWM2A' }, 338 | key: 'P8_19', 339 | muxRegOffset: '0x020', 340 | options: 341 | [ 'gpmc_ad8', 342 | 'lcd_data23', 343 | 'mmc1_dat0', 344 | 'mmc2_dat4', 345 | 'ehrpwm2A', 346 | 'pr1_mii_mt0_clk', 347 | 'NA', 348 | 'gpio0_22' ] }, 349 | P8_20: 350 | { name: 'GPIO1_31', 351 | gpio: 63, 352 | mux: 'gpmc_csn2', 353 | eeprom: 39, 354 | key: 'P8_20', 355 | muxRegOffset: '0x084', 356 | options: 357 | [ 'gpmc_csn2', 358 | 'gpmc_be1n', 359 | 'mmc1_cmd', 360 | 'pr1_edio_data_in7', 361 | 'pr1_edio_data_out7', 362 | 'pr1_pru1_pru_r30_13', 363 | 'pr1_pru1_pru_r31_13', 364 | 'gpio1_31' ] }, 365 | P8_21: 366 | { name: 'GPIO1_30', 367 | gpio: 62, 368 | mux: 'gpmc_csn1', 369 | eeprom: 38, 370 | key: 'P8_21', 371 | muxRegOffset: '0x080', 372 | options: 373 | [ 'gpmc_csn1', 374 | 'gpmc_clk', 375 | 'mmc1_clk', 376 | 'pr1_edio_data_in6', 377 | 'pr1_edio_data_out6', 378 | 'pr1_pru1_pru_r30_12', 379 | 'pr1_pru1_pru_r31_12', 380 | 'gpio1_30' ] }, 381 | P8_22: 382 | { name: 'GPIO1_5', 383 | gpio: 37, 384 | mux: 'gpmc_ad5', 385 | eeprom: 25, 386 | key: 'P8_22', 387 | muxRegOffset: '0x014', 388 | options: 389 | [ 'gpmc_ad5', 390 | 'mmc1_dat5', 391 | 'NA', 392 | 'NA', 393 | 'NA', 394 | 'NA', 395 | 'NA', 396 | 'gpio1_5' ] }, 397 | P8_23: 398 | { name: 'GPIO1_4', 399 | gpio: 36, 400 | mux: 'gpmc_ad4', 401 | eeprom: 24, 402 | key: 'P8_23', 403 | muxRegOffset: '0x010', 404 | options: 405 | [ 'gpmc_ad4', 406 | 'mmc1_dat4', 407 | 'NA', 408 | 'NA', 409 | 'NA', 410 | 'NA', 411 | 'NA', 412 | 'gpio1_4' ] }, 413 | P8_24: 414 | { name: 'GPIO1_1', 415 | gpio: 33, 416 | mux: 'gpmc_ad1', 417 | eeprom: 21, 418 | key: 'P8_24', 419 | muxRegOffset: '0x004', 420 | options: 421 | [ 'gpmc_ad1', 422 | 'mmc1_dat1', 423 | 'NA', 424 | 'NA', 425 | 'NA', 426 | 'NA', 427 | 'NA', 428 | 'gpio1_1' ] }, 429 | P8_25: 430 | { name: 'GPIO1_0', 431 | gpio: 32, 432 | mux: 'gpmc_ad0', 433 | eeprom: 20, 434 | key: 'P8_25', 435 | muxRegOffset: '0x000', 436 | options: 437 | [ 'gpmc_ad0', 438 | 'mmc1_dat0', 439 | 'NA', 440 | 'NA', 441 | 'NA', 442 | 'NA', 443 | 'NA', 444 | 'gpio1_0' ] }, 445 | P8_26: 446 | { name: 'GPIO1_29', 447 | gpio: 61, 448 | mux: 'gpmc_csn0', 449 | eeprom: 37, 450 | key: 'P8_26', 451 | muxRegOffset: '0x07c', 452 | options: 453 | [ 'gpmc_csn0', 454 | 'NA', 455 | 'NA', 456 | 'NA', 457 | 'NA', 458 | 'NA', 459 | 'NA', 460 | 'gpio1_29' ] }, 461 | P8_27: 462 | { name: 'GPIO2_22', 463 | gpio: 86, 464 | mux: 'lcd_vsync', 465 | eeprom: 57, 466 | key: 'P8_27', 467 | muxRegOffset: '0x0e0', 468 | options: 469 | [ 'lcd_vsync', 470 | 'gpmc_a8', 471 | 'NA', 472 | 'pr1_edio_data_in2', 473 | 'pr1_edio_data_out2', 474 | 'pr1_pru1_pru_r30_8', 475 | 'pr1_pru1_pru_r31_8', 476 | 'gpio2_22' ] }, 477 | P8_28: 478 | { name: 'GPIO2_24', 479 | gpio: 88, 480 | mux: 'lcd_pclk', 481 | eeprom: 59, 482 | key: 'P8_28', 483 | muxRegOffset: '0x0e8', 484 | options: 485 | [ 'lcd_pclk', 486 | 'gpmc_a10', 487 | 'pr1_mii0_crs', 488 | 'pr1_edio_data_in4', 489 | 'pr1_edio_data_out4', 490 | 'pr1_pru1_pru_r30_10', 491 | 'pr1_pru1_pru_r31_10', 492 | 'gpio2_24' ] }, 493 | P8_29: 494 | { name: 'GPIO2_23', 495 | gpio: 87, 496 | mux: 'lcd_hsync', 497 | eeprom: 58, 498 | key: 'P8_29', 499 | muxRegOffset: '0x0e4', 500 | options: 501 | [ 'lcd_hsync', 502 | 'gpmc_a9', 503 | 'NA', 504 | 'pr1_edio_data_in3', 505 | 'pr1_edio_data_out3', 506 | 'pr1_pru1_pru_r30_9', 507 | 'pr1_pru1_pru_r31_9', 508 | 'gpio2_23' ] }, 509 | P8_30: 510 | { name: 'GPIO2_25', 511 | gpio: 89, 512 | mux: 'lcd_ac_bias_en', 513 | eeprom: 60, 514 | key: 'P8_30', 515 | muxRegOffset: '0x0ec', 516 | options: 517 | [ 'lcd_ac_bias_en', 518 | 'gpmc_a11', 519 | 'pr1_mii1_crs', 520 | 'pr1_edio_data_in5', 521 | 'pr1_edio_data_out5', 522 | 'pr1_pru1_pru_r30_11', 523 | 'pr1_pru1_pru_r31_11', 524 | 'gpio2_25' ] }, 525 | P8_31: 526 | { name: 'UART5_CTSN', 527 | gpio: 10, 528 | mux: 'lcd_data14', 529 | eeprom: 7, 530 | key: 'P8_31', 531 | muxRegOffset: '0x0d8', 532 | options: 533 | [ 'lcd_data14', 534 | 'gpmc_a18', 535 | 'NA', 536 | 'mcasp0_axr1', 537 | 'NA', 538 | 'NA', 539 | 'NA', 540 | 'gpio0_10' ] }, 541 | P8_32: 542 | { name: 'UART5_RTSN', 543 | gpio: 11, 544 | mux: 'lcd_data15', 545 | eeprom: 8, 546 | key: 'P8_32', 547 | muxRegOffset: '0x0dc', 548 | options: 549 | [ 'lcd_data15', 550 | 'gpmc_a19', 551 | 'NA', 552 | 'mcasp0_ahclkx', 553 | 'mcasp0_axr3', 554 | 'NA', 555 | 'NA', 556 | 'gpio0_11' ] }, 557 | P8_33: 558 | { name: 'UART4_RTSN', 559 | gpio: 9, 560 | mux: 'lcd_data13', 561 | eeprom: 6, 562 | key: 'P8_33', 563 | muxRegOffset: '0x0d4', 564 | options: 565 | [ 'lcd_data13', 566 | 'gpmc_a17', 567 | 'NA', 568 | 'mcasp0_fsr', 569 | 'mcasp0_axr3', 570 | 'NA', 571 | 'NA', 572 | 'gpio0_9' ] }, 573 | P8_34: 574 | { name: 'UART3_RTSN', 575 | gpio: 81, 576 | mux: 'lcd_data11', 577 | eeprom: 56, 578 | pwm: 579 | { module: 'ehrpwm1', 580 | muxmode: 2, 581 | path: 'ehrpwm.1:1', 582 | name: 'EHRPWM1B' }, 583 | key: 'P8_34', 584 | muxRegOffset: '0x0cc', 585 | options: 586 | [ 'lcd_data11', 587 | 'gpmc_a15', 588 | 'NA', 589 | 'mcasp0_ahclkr', 590 | 'mcasp0_axr2', 591 | 'NA', 592 | 'NA', 593 | 'gpio2_17' ] }, 594 | P8_35: 595 | { name: 'UART4_CTSN', 596 | gpio: 8, 597 | mux: 'lcd_data12', 598 | eeprom: 5, 599 | key: 'P8_35', 600 | muxRegOffset: '0x0d0', 601 | options: 602 | [ 'lcd_data12', 603 | 'gpmc_a16', 604 | 'NA', 605 | 'mcasp0_aclkr', 606 | 'mcasp0_axr2', 607 | 'NA', 608 | 'NA', 609 | 'gpio0_8' ] }, 610 | P8_36: 611 | { name: 'UART3_CTSN', 612 | gpio: 80, 613 | mux: 'lcd_data10', 614 | eeprom: 55, 615 | pwm: 616 | { module: 'ehrpwm1', 617 | muxmode: 2, 618 | path: 'ehrpwm.1:0', 619 | name: 'EHRPWM1A' }, 620 | key: 'P8_36', 621 | muxRegOffset: '0x0c8', 622 | options: 623 | [ 'lcd_data10', 624 | 'gpmc_a14', 625 | 'ehrpwm1A', 626 | 'mcasp0_axr0', 627 | 'mcasp0_axr0', 628 | 'pr1_mii0_rxd1', 629 | 'uart3_ctsn', 630 | 'gpio2_16' ] }, 631 | P8_37: 632 | { name: 'UART5_TXD', 633 | gpio: 78, 634 | mux: 'lcd_data8', 635 | eeprom: 53, 636 | key: 'P8_37', 637 | muxRegOffset: '0x0c0', 638 | options: 639 | [ 'lcd_data8', 640 | 'gpmc_a12', 641 | 'NA', 642 | 'mcasp0_aclkx', 643 | 'NA', 644 | 'NA', 645 | 'uart2_ctsn', 646 | 'gpio2_14' ] }, 647 | P8_38: 648 | { name: 'UART5_RXD', 649 | gpio: 79, 650 | mux: 'lcd_data9', 651 | eeprom: 54, 652 | key: 'P8_38', 653 | muxRegOffset: '0x0c4', 654 | options: 655 | [ 'lcd_data9', 656 | 'gpmc_a13', 657 | 'NA', 658 | 'mcasp0_fsx', 659 | 'NA', 660 | 'NA', 661 | 'uart2_rtsn', 662 | 'gpio2_15' ] }, 663 | P8_39: 664 | { name: 'GPIO2_12', 665 | gpio: 76, 666 | mux: 'lcd_data6', 667 | eeprom: 51, 668 | key: 'P8_39', 669 | muxRegOffset: '0x0b8', 670 | options: 671 | [ 'lcd_data6', 672 | 'gpmc_a6', 673 | 'pr1_edio_data_in6', 674 | 'eqep2_index', 675 | 'pr1_edio_data_out6', 676 | 'pr1_pru1_pru_r30_6', 677 | 'pr1_pru1_pru_r31_6', 678 | 'gpio2_12' ] }, 679 | P8_40: 680 | { name: 'GPIO2_13', 681 | gpio: 77, 682 | mux: 'lcd_data7', 683 | eeprom: 52, 684 | key: 'P8_40', 685 | muxRegOffset: '0x0bc', 686 | options: 687 | [ 'lcd_data7', 688 | 'gpmc_a7', 689 | 'pr1_edio_data_in7', 690 | 'eqep2_strobe', 691 | 'pr1_pru1_pru_r30_7', 692 | 'pr1_pru_pru1_r30_7', 693 | 'pr1_pru1_pru_r31_7', 694 | 'gpio2_13' ] }, 695 | P8_41: 696 | { name: 'GPIO2_10', 697 | gpio: 74, 698 | mux: 'lcd_data4', 699 | eeprom: 49, 700 | key: 'P8_41', 701 | muxRegOffset: '0x0b0', 702 | options: 703 | [ 'lcd_data4', 704 | 'gpmc_a4', 705 | 'pr1_mii0_txd1', 706 | 'eQEP2A_in', 707 | 'NA', 708 | 'pr1_pru1_pru_r30_4', 709 | 'pr1_pru1_pru_r31_4', 710 | 'gpio2_10' ] }, 711 | P8_42: 712 | { name: 'GPIO2_11', 713 | gpio: 75, 714 | mux: 'lcd_data5', 715 | eeprom: 50, 716 | key: 'P8_42', 717 | muxRegOffset: '0x0b4', 718 | options: 719 | [ 'lcd_data5', 720 | 'gpmc_a5', 721 | 'pr1_mii0_txd0', 722 | 'eqep2b_in', 723 | 'NA', 724 | 'pr1_pru1_pru_r30_5', 725 | 'pr1_pru1_pru_r31_5', 726 | 'gpio2_11' ] }, 727 | P8_43: 728 | { name: 'GPIO2_8', 729 | gpio: 72, 730 | mux: 'lcd_data2', 731 | eeprom: 47, 732 | key: 'P8_43', 733 | muxRegOffset: '0x0a8', 734 | options: 735 | [ 'lcd_data2', 736 | 'gpmc_a2', 737 | 'pr1_mii0_txd3', 738 | 'ehrpwm2_tripzone_input', 739 | 'NA', 740 | 'pr1_pru1_pru_r30_2', 741 | 'pr1_pru1_pru_r31_2', 742 | 'gpio2_8' ] }, 743 | P8_44: 744 | { name: 'GPIO2_9', 745 | gpio: 73, 746 | mux: 'lcd_data3', 747 | eeprom: 48, 748 | key: 'P8_44', 749 | muxRegOffset: '0x0ac', 750 | options: 751 | [ 'lcd_data3', 752 | 'gpmc_a3', 753 | 'pr1_mii0_txd2', 754 | 'ehrpwm0_synco', 755 | 'NA', 756 | 'pr1_pru1_pru_r30_3', 757 | 'pr1_pru1_pru_r31_3', 758 | 'gpio2_9' ] }, 759 | P8_45: 760 | { name: 'GPIO2_6', 761 | gpio: 70, 762 | mux: 'lcd_data0', 763 | eeprom: 45, 764 | pwm: 765 | { module: 'ehrpwm2', 766 | muxmode: 3, 767 | path: 'ehrpwm.2:0', 768 | name: 'EHRPWM2A' }, 769 | key: 'P8_45', 770 | muxRegOffset: '0x0a0', 771 | options: 772 | [ 'lcd_data0', 773 | 'gpmc_a0', 774 | 'pr1_mii_mt0_clk', 775 | 'ehrpwm2A', 776 | 'NA', 777 | 'pr1_pru1_pru_r30_0', 778 | 'pr1_pru1_pru_r31_0', 779 | 'gpio2_6' ] }, 780 | P8_46: 781 | { name: 'GPIO2_7', 782 | gpio: 71, 783 | mux: 'lcd_data1', 784 | eeprom: 46, 785 | pwm: 786 | { module: 'ehrpwm2', 787 | muxmode: 3, 788 | path: 'ehrpwm.2:1', 789 | name: 'EHRPWM2B' }, 790 | key: 'P8_46', 791 | muxRegOffset: '0x0a4', 792 | options: 793 | [ 'lcd_data1', 794 | 'gpmc_a1', 795 | 'pr1_mii0_txen', 796 | 'ehrpwm2B', 797 | 'NA', 798 | 'pr1_pru1_pru_r30_1', 799 | 'pr1_pru1_pru_r31_1', 800 | 'gpio2_7' ] }, 801 | P9_1: { name: 'DGND', key: 'P9_1' }, 802 | P9_2: { name: 'DGND', key: 'P9_2' }, 803 | P9_3: { name: 'VDD_3V3', key: 'P9_3' }, 804 | P9_4: { name: 'VDD_3V3', key: 'P9_4' }, 805 | P9_5: { name: 'VDD_5V', key: 'P9_5' }, 806 | P9_6: { name: 'VDD_5V', key: 'P9_6' }, 807 | P9_7: { name: 'SYS_5V', key: 'P9_7' }, 808 | P9_8: { name: 'SYS_5V', key: 'P9_8' }, 809 | P9_9: { name: 'PWR_BUT', key: 'P9_9' }, 810 | P9_10: { name: 'SYS_RESETn', key: 'P9_10' }, 811 | P9_11: 812 | { name: 'UART4_RXD', 813 | gpio: 30, 814 | mux: 'gpmc_wait0', 815 | eeprom: 18, 816 | key: 'P9_11', 817 | muxRegOffset: '0x070', 818 | options: 819 | [ 'gpmc_wait0', 820 | 'mii2_crs', 821 | 'NA', 822 | 'rmii2_crs_dv', 823 | 'mmc1_sdcd', 824 | 'NA', 825 | 'NA', 826 | 'gpio0_30' ] }, 827 | P9_12: 828 | { name: 'GPIO1_28', 829 | gpio: 60, 830 | mux: 'gpmc_ben1', 831 | eeprom: 36, 832 | key: 'P9_12', 833 | muxRegOffset: '0x078', 834 | options: 835 | [ 'gpmc_ben1', 836 | 'mii2_col', 837 | 'NA', 838 | 'mmc2_dat3', 839 | 'NA', 840 | 'NA', 841 | 'mcasp0_aclkr', 842 | 'gpio1_28' ] }, 843 | P9_13: 844 | { name: 'UART4_TXD', 845 | gpio: 31, 846 | mux: 'gpmc_wpn', 847 | eeprom: 19, 848 | key: 'P9_13', 849 | muxRegOffset: '0x074', 850 | options: 851 | [ 'gpmc_wpn', 852 | 'mii2_rxerr', 853 | 'NA', 854 | 'rmii2_rxerr', 855 | 'mmc2_sdcd', 856 | 'NA', 857 | 'NA', 858 | 'gpio0_31' ] }, 859 | P9_14: 860 | { name: 'EHRPWM1A', 861 | gpio: 50, 862 | mux: 'gpmc_a2', 863 | eeprom: 34, 864 | pwm: 865 | { module: 'ehrpwm1', 866 | muxmode: 6, 867 | path: 'ehrpwm.1:0', 868 | name: 'EHRPWM1A' }, 869 | key: 'P9_14', 870 | muxRegOffset: '0x048', 871 | options: 872 | [ 'gpmc_a2', 873 | 'gmii2_txd3', 874 | 'rgmii2_td3', 875 | 'mmc2_dat1', 876 | 'gpmc_a18', 877 | 'pr1_mii1_txd2', 878 | 'ehrpwm1A', 879 | 'gpio1_18' ] }, 880 | P9_15: 881 | { name: 'GPIO1_16', 882 | gpio: 48, 883 | mux: 'mii1_rxd3', 884 | eeprom: 32, 885 | key: 'P9_15', 886 | muxRegOffset: '0x134', 887 | options: 888 | [ 'mii1_rxd3', 889 | 'NA', 890 | 'rgmii1_rd3', 891 | 'mmc0_dat5', 892 | 'mmc1_dat2', 893 | 'NA', 894 | 'mcasp0_axr0', 895 | 'gpio2_18' ] }, 896 | P9_16: 897 | { name: 'EHRPWM1B', 898 | gpio: 51, 899 | mux: 'gpmc_a3', 900 | eeprom: 35, 901 | pwm: 902 | { module: 'ehrpwm1', 903 | muxmode: 6, 904 | path: 'ehrpwm.1:1', 905 | name: 'EHRPWM1B' }, 906 | key: 'P9_16', 907 | muxRegOffset: '0x04c', 908 | options: 909 | [ 'gpmc_a3', 910 | 'gmii2_txd2', 911 | 'rgmii2_td2', 912 | 'mmc2_dat2', 913 | 'gpmc_a19', 914 | 'pr1_mii1_txd1', 915 | 'ehrpwm1B', 916 | 'gpio1_19' ] }, 917 | P9_17: 918 | { name: 'I2C1_SCL', 919 | gpio: 5, 920 | mux: 'spi0_cs0', 921 | eeprom: 3, 922 | key: 'P9_17', 923 | muxRegOffset: '0x15c', 924 | options: 925 | [ 'spi0_cs0', 926 | 'mmc2_sdwp', 927 | 'i2c1_scl', 928 | 'NA', 929 | 'NA', 930 | 'NA', 931 | 'NA', 932 | 'gpio0_5' ] }, 933 | P9_18: 934 | { name: 'I2C1_SDA', 935 | gpio: 4, 936 | mux: 'spi0_d1', 937 | eeprom: 2, 938 | key: 'P9_18', 939 | muxRegOffset: '0x158', 940 | options: 941 | [ 'spi0_d1', 942 | 'mmc1_sdwp', 943 | 'i2c1_sda', 944 | 'NA', 945 | 'NA', 946 | 'NA', 947 | 'NA', 948 | 'gpio0_4' ] }, 949 | P9_19: 950 | { name: 'I2C2_SCL', 951 | gpio: 13, 952 | mux: 'uart1_rtsn', 953 | eeprom: 9, 954 | key: 'P9_19', 955 | muxRegOffset: '0x17c', 956 | options: 957 | [ 'uart1_rtsn', 958 | 'NA', 959 | 'd_can0_rx', 960 | 'i2c2_scl', 961 | 'spi1_cs1', 962 | 'NA', 963 | 'NA', 964 | 'gpio0_13' ] }, 965 | P9_20: 966 | { name: 'I2C2_SDA', 967 | gpio: 12, 968 | mux: 'uart1_ctsn', 969 | eeprom: 10, 970 | key: 'P9_20', 971 | muxRegOffset: '0x178', 972 | options: 973 | [ 'uart1_ctsn', 974 | 'NA', 975 | 'd_can0_tx', 976 | 'i2c2_sda', 977 | 'spi1_cs0', 978 | 'NA', 979 | 'NA', 980 | 'gpio0_12' ] }, 981 | P9_21: 982 | { name: 'UART2_TXD', 983 | gpio: 3, 984 | mux: 'spi0_d0', 985 | eeprom: 1, 986 | pwm: 987 | { module: 'ehrpwm0', 988 | muxmode: 3, 989 | path: 'ehrpwm.0:1', 990 | name: 'EHRPWM0B' }, 991 | key: 'P9_21', 992 | muxRegOffset: '0x154', 993 | options: 994 | [ 'spi0_d0', 995 | 'uart2_txd', 996 | 'i2c2_scl', 997 | 'NA', 998 | 'NA', 999 | 'NA', 1000 | 'NA', 1001 | 'gpio0_3' ] }, 1002 | P9_22: 1003 | { name: 'UART2_RXD', 1004 | gpio: 2, 1005 | mux: 'spi0_sclk', 1006 | eeprom: 0, 1007 | pwm: 1008 | { module: 'ehrpwm0', 1009 | muxmode: 3, 1010 | path: 'ehrpwm.0:0', 1011 | name: 'EHRPWM0A' }, 1012 | key: 'P9_22', 1013 | muxRegOffset: '0x150', 1014 | options: 1015 | [ 'spi0_sclk', 1016 | 'uart2_rxd', 1017 | 'i2c2_sda', 1018 | 'NA', 1019 | 'NA', 1020 | 'NA', 1021 | 'NA', 1022 | 'gpio0_2' ] }, 1023 | P9_23: 1024 | { name: 'GPIO1_17', 1025 | gpio: 49, 1026 | mux: 'gpmc_a1', 1027 | eeprom: 33, 1028 | key: 'P9_23', 1029 | muxRegOffset: '0x044', 1030 | options: 1031 | [ 'gpmc_a1', 1032 | 'gmii2_rxdv', 1033 | 'rgmii2_rctl', 1034 | 'mmc2_dat0', 1035 | 'gpmc_a17', 1036 | 'pr1_mii1_txd3', 1037 | 'ehrpwm0_synco', 1038 | 'gpio1_17' ] }, 1039 | P9_24: 1040 | { name: 'UART1_TXD', 1041 | gpio: 15, 1042 | mux: 'uart1_txd', 1043 | eeprom: 12, 1044 | key: 'P9_24', 1045 | muxRegOffset: '0x184', 1046 | options: 1047 | [ 'uart1_txd', 1048 | 'mmc2_sdwp', 1049 | 'd_can1_rx', 1050 | 'i2c1_scl', 1051 | 'NA', 1052 | 'pr1_uart0_txd_mux1', 1053 | 'NA', 1054 | 'gpio0_15' ] }, 1055 | P9_25: 1056 | { name: 'GPIO3_21', 1057 | gpio: 117, 1058 | mux: 'mcasp0_ahclkx', 1059 | eeprom: 66, 1060 | key: 'P9_25', 1061 | muxRegOffset: '0x1ac', 1062 | options: 1063 | [ 'mcasp0_ahclkx', 1064 | 'NA', 1065 | 'mcasp0_axr3', 1066 | 'mcasp1_axr1', 1067 | 'NA', 1068 | 'NA', 1069 | 'NA', 1070 | 'gpio3_21' ] }, 1071 | P9_26: 1072 | { name: 'UART1_RXD', 1073 | gpio: 14, 1074 | mux: 'uart1_rxd', 1075 | eeprom: 11, 1076 | key: 'P9_26', 1077 | muxRegOffset: '0x180', 1078 | options: 1079 | [ 'uart1_rxd', 1080 | 'mmc1_sdwp', 1081 | 'd_can1_tx', 1082 | 'i2c1_sda', 1083 | 'NA', 1084 | 'pr1_uart0_rxd_mux1', 1085 | 'NA', 1086 | 'gpio0_14' ] }, 1087 | P9_27: 1088 | { name: 'GPIO3_19', 1089 | gpio: 115, 1090 | mux: 'mcasp0_fsr', 1091 | eeprom: 64, 1092 | key: 'P9_27', 1093 | muxRegOffset: '0x1a4', 1094 | options: 1095 | [ 'mcasp0_fsr', 1096 | 'NA', 1097 | 'mcasp0_axr3', 1098 | 'mcasp1_fsx', 1099 | 'NA', 1100 | 'pr1_pru0_pru_r30_5', 1101 | 'NA', 1102 | 'gpio3_19' ] }, 1103 | P9_28: 1104 | { name: 'SPI1_CS0', 1105 | gpio: 113, 1106 | mux: 'mcasp0_ahclkr', 1107 | eeprom: 63, 1108 | pwm: 1109 | { module: 'ecap2', 1110 | muxmode: 4, 1111 | path: 'ecap.2', 1112 | name: 'ECAPPWM2' }, 1113 | key: 'P9_28', 1114 | muxRegOffset: '0x19c', 1115 | options: 1116 | [ 'mcasp0_ahclkr', 1117 | 'NA', 1118 | 'mcasp0_axr2', 1119 | 'spi1_cs0', 1120 | 'eCAP2_in_PWM2_out', 1121 | 'NA', 1122 | 'NA', 1123 | 'gpio3_17' ] }, 1124 | P9_29: 1125 | { name: 'SPI1_D0', 1126 | gpio: 111, 1127 | mux: 'mcasp0_fsx', 1128 | eeprom: 61, 1129 | pwm: 1130 | { module: 'ehrpwm0', 1131 | muxmode: 1, 1132 | path: 'ehrpwm.0:1', 1133 | name: 'EHRPWM0B' }, 1134 | key: 'P9_29', 1135 | muxRegOffset: '0x194', 1136 | options: 1137 | [ 'mcasp0_fsx', 1138 | 'ehrpwm0B', 1139 | 'NA', 1140 | 'spi1_d0', 1141 | 'mmc1_sdcd', 1142 | 'NA', 1143 | 'NA', 1144 | 'gpio3_15' ] }, 1145 | P9_30: 1146 | { name: 'SPI1_D1', 1147 | gpio: 112, 1148 | mux: 'mcasp0_axr0', 1149 | eeprom: 62, 1150 | key: 'P9_30', 1151 | muxRegOffset: '0x198', 1152 | options: 1153 | [ 'mcasp0_axr0', 1154 | 'NA', 1155 | 'NA', 1156 | 'spi1_d1', 1157 | 'mmc2_sdcd', 1158 | 'NA', 1159 | 'NA', 1160 | 'gpio3_16' ] }, 1161 | P9_31: 1162 | { name: 'SPI1_SCLK', 1163 | gpio: 110, 1164 | mux: 'mcasp0_aclkx', 1165 | eeprom: 65, 1166 | pwm: 1167 | { module: 'ehrpwm0', 1168 | index: 0, 1169 | muxmode: 1, 1170 | path: 'ehrpwm.0:0', 1171 | name: 'EHRPWM0A' }, 1172 | key: 'P9_31', 1173 | muxRegOffset: '0x190', 1174 | options: 1175 | [ 'mcasp0_aclkx', 1176 | 'ehrpwm0A', 1177 | 'NA', 1178 | 'spi1_sclk', 1179 | 'mmc0_sdcd', 1180 | 'NA', 1181 | 'NA', 1182 | 'gpio3_14' ] }, 1183 | P9_32: { name: 'VDD_ADC', key: 'P9_32' }, 1184 | P9_33: 1185 | { name: 'AIN4', 1186 | ain: 4, 1187 | eeprom: 71, 1188 | scale: 4096, 1189 | key: 'P9_33' }, 1190 | P9_34: { name: 'GNDA_ADC', key: 'P9_34' }, 1191 | P9_35: 1192 | { name: 'AIN6', 1193 | ain: 6, 1194 | eeprom: 73, 1195 | scale: 4096, 1196 | key: 'P9_35' }, 1197 | P9_36: 1198 | { name: 'AIN5', 1199 | ain: 5, 1200 | eeprom: 72, 1201 | scale: 4096, 1202 | key: 'P9_36' }, 1203 | P9_37: 1204 | { name: 'AIN2', 1205 | ain: 2, 1206 | eeprom: 69, 1207 | scale: 4096, 1208 | key: 'P9_37' }, 1209 | P9_38: 1210 | { name: 'AIN3', 1211 | ain: 3, 1212 | eeprom: 70, 1213 | scale: 4096, 1214 | key: 'P9_38' }, 1215 | P9_39: 1216 | { name: 'AIN0', 1217 | ain: 0, 1218 | eeprom: 67, 1219 | scale: 4096, 1220 | key: 'P9_39' }, 1221 | P9_40: 1222 | { name: 'AIN1', 1223 | ain: 1, 1224 | eeprom: 68, 1225 | scale: 4096, 1226 | key: 'P9_40' }, 1227 | P9_41: 1228 | { name: 'CLKOUT2', 1229 | gpio: 20, 1230 | mux: 'xdma_event_intr1', 1231 | eeprom: 13, 1232 | key: 'P9_41', 1233 | muxRegOffset: '0x1b4', 1234 | options: 1235 | [ 'xdma_event_intr1', 1236 | 'NA', 1237 | 'NA', 1238 | 'clkout2', 1239 | 'NA', 1240 | 'NA', 1241 | 'NA', 1242 | 'gpio0_20' ] }, 1243 | P9_42: 1244 | { name: 'GPIO0_7', 1245 | gpio: 7, 1246 | mux: 'ecap0_in_pwm0_out', 1247 | eeprom: 4, 1248 | pwm: 1249 | { module: 'ecap0', 1250 | index: 0, 1251 | muxmode: 0, 1252 | path: 'ecap.0', 1253 | name: 'ECAPPWM0' }, 1254 | key: 'P9_42', 1255 | muxRegOffset: '0x164', 1256 | options: 1257 | [ 'eCAP0_in_PWM0_out', 1258 | 'uart3_txd', 1259 | 'spi1_cs1', 1260 | 'pr1_ecap0_ecap_capin_apwm_o', 1261 | 'spi1_sclk', 1262 | 'mmc0_sdwp', 1263 | 'xdma_event_intr2', 1264 | 'gpio0_7' ] }, 1265 | P9_43: { name: 'DGND', key: 'P9_43' }, 1266 | P9_44: { name: 'DGND', key: 'P9_44' }, 1267 | P9_45: { name: 'DGND', key: 'P9_45' }, 1268 | P9_46: { name: 'DGND', key: 'P9_46' } } 1269 | --------------------------------------------------------------------------------