|
| 1 | +var SPI = require('pi-spi'); |
| 2 | + |
| 3 | + |
| 4 | +// The SPI linux device. Either /dev/spidev0.0 or /dev/spidev0.1 |
| 5 | +var spidev = '/dev/spidev0.0'; |
| 6 | + |
| 7 | +// The handle to the device driver |
| 8 | +var spiDevice = null; |
| 9 | + |
| 10 | + |
| 11 | + |
| 12 | +// A collection of all connected sockets. |
| 13 | +// Maps socketid => { socket: sockethandle, id: socketid } |
| 14 | +var connections = {}; |
| 15 | + |
| 16 | +exports.settings={}; |
| 17 | +//These are dynamically updated by the runtime |
| 18 | +//settings.appname - the app id (folder) where your app is installed |
| 19 | +//settings.viewpath - prefix to where your view html files are located |
| 20 | +//settings.staticurl - base url path to static assets /static/apps/appname |
| 21 | +//settings.appurl - base url path to this app /app/appname |
| 22 | +//settings.device_name - name given to this coder by the user, Ie."Billy's Coder" |
| 23 | +//settings.coder_owner - name of the user, Ie. "Suzie Q." |
| 24 | +//settings.coder_color - hex css color given to this coder. |
| 25 | + |
| 26 | +// Incoming get routes that our app knows how to respond to |
| 27 | +exports.get_routes = [ |
| 28 | + { path:'/', handler:'index_handler' }, // Render out main html page |
| 29 | +]; |
| 30 | + |
| 31 | +// Incoming post routes that our app knows how to respond to |
| 32 | +// (None in this example) |
| 33 | +exports.post_routes = [ |
| 34 | +]; |
| 35 | + |
| 36 | +// Incoming socket events that this module will expose. |
| 37 | +exports.socketio_routes = [ |
| 38 | + { key:'connect', handler:'on_socket_connect' }, // sent by client once socket is loaded |
| 39 | +]; |
| 40 | + |
| 41 | + |
| 42 | + |
| 43 | +// |
| 44 | +// Handles sending the HTML page to the browser |
| 45 | +// |
| 46 | +exports.index_handler = function( req, res ) { |
| 47 | + // Set up some template variables that are substituted in our HTML. |
| 48 | + // Look in the HTML head tag to see where these are inserted. |
| 49 | + var tmplvars = {}; |
| 50 | + tmplvars['static_url'] = exports.settings.staticurl; |
| 51 | + tmplvars['app_name'] = exports.settings.appname; |
| 52 | + tmplvars['app_url'] = exports.settings.appurl; |
| 53 | + tmplvars['device_name'] = exports.settings.device_name; |
| 54 | + |
| 55 | + // Send the HTML document to the web browser. |
| 56 | + res.render( exports.settings.viewpath + '/index', tmplvars ); |
| 57 | +}; |
| 58 | + |
| 59 | + |
| 60 | +// |
| 61 | +// Respond to the "connect" message sent by a new socket client. |
| 62 | +// |
| 63 | +// We do two things here: |
| 64 | +// 1. save the socket object into the "connections" variable so we can talk to it later. |
| 65 | +// 2. initialize the SPI device if this is the first time a socket has connected. |
| 66 | +// |
| 67 | +exports.on_socket_connect = function( socket, data ) { |
| 68 | + console.log( 'socket connect from ID: ' + socket.socketID ); |
| 69 | + console.log( data ); |
| 70 | + |
| 71 | + // Enable the SPI device if this is the first connection |
| 72 | + if ( Object.keys( connections ).length <= 0 ) { |
| 73 | + enableSPI(); |
| 74 | + } |
| 75 | + |
| 76 | + // Store information about this socket so we can communicate with |
| 77 | + // all connected sockets in the future. |
| 78 | + connections[socket.socketID] = { |
| 79 | + socket: socket, |
| 80 | + id: socket.socketID |
| 81 | + }; |
| 82 | + |
| 83 | + // Watch for this socket to disconnect so that we can remove it from |
| 84 | + // our collection of connected sockets. |
| 85 | + socket.on('disconnect', function() { |
| 86 | + console.log( 'socket disconnect from ID: ' + socket.socketID ); |
| 87 | + delete connections[socket.socketID]; |
| 88 | + |
| 89 | + //Free up the GPIO when the last socket disconnects |
| 90 | + if ( Object.keys( connections ).length <= 0 ) { |
| 91 | + disableSPI(); |
| 92 | + connected = false; |
| 93 | + spiDevice = null; |
| 94 | + } |
| 95 | + }); |
| 96 | + |
| 97 | +}; |
| 98 | + |
| 99 | + |
| 100 | + |
| 101 | + |
| 102 | + |
| 103 | +// |
| 104 | +// This is called once from our first socket connection. |
| 105 | +// - set up the SPI device |
| 106 | +// - read input from the device and send spiupdate events |
| 107 | +// |
| 108 | +var updateInterval; |
| 109 | +var enableSPI = function() { |
| 110 | + |
| 111 | + // Set up the SPI device |
| 112 | + console.log("Setting up SPI on " + spidev ); |
| 113 | + spiDevice = SPI.initialize( spidev ); |
| 114 | + |
| 115 | + |
| 116 | + //Poll the device for updates once a second. |
| 117 | + updateInterval = setInterval( readADCData, 1000 ); |
| 118 | + |
| 119 | + |
| 120 | +}; |
| 121 | + |
| 122 | +// |
| 123 | +// This is called when the last socket disconnects. |
| 124 | +// It releases our GPIO pins so they can be used by another program. |
| 125 | +// |
| 126 | +var disableSPI = function() { |
| 127 | + |
| 128 | + console.log("Disabling SPI device" + spidev ); |
| 129 | + |
| 130 | + clearInterval( updateInterval ); |
| 131 | + spiDevice.close(); |
| 132 | + |
| 133 | +}; |
| 134 | + |
| 135 | +var toBin = function( d ) { |
| 136 | + return ("00000000" + d.toString(2)).substr( -8 ); |
| 137 | +}; |
| 138 | + |
| 139 | +// |
| 140 | +// Reads channel 0 analog value from an MCP3008 ADC chip |
| 141 | +// |
| 142 | +var readADCData = function() { |
| 143 | + // Recall that this code is running on the device. We need to send a |
| 144 | + // socket message with the data to our javascript in the |
| 145 | + // web browser. In fact, we need to send this data to every connected |
| 146 | + // socket, since there may be more than one browser window looking at |
| 147 | + // this page. |
| 148 | + |
| 149 | + // The message used to tell an MCP3008 ADC chip to return the |
| 150 | + // analog reading of channel 0; |
| 151 | + var channel = 0; |
| 152 | + var message = new Buffer([1, (8+channel)<<4, 0]); |
| 153 | + |
| 154 | + spiDevice.transfer( message, message.length, function( error, data ) { |
| 155 | + if ( error ) { |
| 156 | + console.log( "read error " + error ); |
| 157 | + } else { |
| 158 | + |
| 159 | + //last 2 bits of 2nd byte, shifted left 8 bits, added to all 8 bits of third byte = 10 data bits. |
| 160 | + var val = ((data[1]&3) << 8) + data[2]; |
| 161 | + //val = data[2]; |
| 162 | + console.log( "raw data: " + toBin( data[0] ) + " " + toBin( data[1] ) + " " + toBin( data[2] ) ); |
| 163 | + //console.log( "value: " + val ); |
| 164 | + |
| 165 | + // Iterate through all of our socket connections |
| 166 | + for ( var socketid in connections ) { |
| 167 | + // Get the socket object for this socket |
| 168 | + var socket = connections[socketid].socket; |
| 169 | + |
| 170 | + // The "appdata" event will be received by the Coder.socketConnection |
| 171 | + // object in the front end code and sent to the appropriate listener |
| 172 | + // that we've defined. |
| 173 | + // The "buttonupdate" key refers to a listener we set up on the front |
| 174 | + // end with the code: |
| 175 | + // Coder.socketConnection.addListener( "buttonupdate", function... ) |
| 176 | + socket.emit( "appdata", { |
| 177 | + key: "analogdata", |
| 178 | + data: val |
| 179 | + }); |
| 180 | + } |
| 181 | + |
| 182 | + |
| 183 | + } |
| 184 | + }); |
| 185 | + |
| 186 | +}; |
| 187 | + |
| 188 | + |
| 189 | +// |
| 190 | +// Called by Coder whenever this module is reloaded. This usually happens when |
| 191 | +// you save your code in the editor. This is a good place to destroy any intervals |
| 192 | +// or clean up any long running code or handles. |
| 193 | +// |
| 194 | +exports.on_destroy = function() { |
| 195 | + if ( spiDevice !== null ) { |
| 196 | + disableSPI(); |
| 197 | + } |
| 198 | + |
| 199 | +}; |
| 200 | + |
| 201 | + |
| 202 | + |
0 commit comments