UNPKG

ble-ble113

Version:

Library to run the Bluetooth BLE113 Tessel Module.

269 lines (215 loc) 8.02 kB
var tessel = require('tessel'); var bgLib = require('bglib'); bgLib.setPacketMode(1); var events = require('events'); var util = require('util'); var DEBUG = 1; function Messenger(hardware) { this.uart = hardware.UART({baudrate:9600}); this.resetPin = hardware.gpio(3); this.awaitingResponse = []; this.uart.on('data', this.parseIncomingPackets.bind(this)); this.commandPacketTimeoutDuration = 10000; // Reset the module to clear any possible comms issues this.resetModule(); } util.inherits(Messenger, events.EventEmitter); Messenger.prototype.resetModule = function() { this.resetPin.output().low(); this.resetPin.high(); } Messenger.prototype.verifyCommunication = function() { var self = this; this.execute(bgLib.api.systemHello, function(err) { self.emit('connected', err); }); } Messenger.prototype.startScanning = function(callback) { var self = this; this.execute(bgLib.api.gapDiscover, [bgLib.GAPDiscoverMode.gap_discover_generic], function(err, response) { console.log(err, response); callback && callback(err, response.result); self.emit('scanStart', err, response.result); }); } Messenger.prototype.stopScanning = function(callback) { var self = this; this.execute(bgLib.api.gapEndProcedure, function(err, response) { callback && callback(err, response.result); self.emit('scanStop', err, response.result); }); } Messenger.prototype.startAdvertising = function(callback) { this.execute(bgLib.api.gapSetMode, [bgLib.GAPDiscoverableModes.gap_general_discoverable, bgLib.GAPConnectableMode.gap_directed_connectable], callback); } Messenger.prototype.writeValue = function(handle, value, callback) { var self = this; this.execute(bgLib.api.attributesWrite, [handle, 0, value], function(err, response) { callback && callback(err, response); self.emit('valueWritten', err, response); }); } Messenger.prototype.readValue = function(handle, callback) { var self = this; // Execute the read this.execute(bgLib.api.attributesRead, [handle, 0], function(err, response) { // Call callback with value callback && callback(err, response.value); // Emit event self.emit('valueRead', err, response.value); }); } Messenger.prototype.debugPacket = function(packet) { for (var i = 0; i < packet.length; i++) { console.log("Byte at index", i, "is", packet[i]); } } Messenger.prototype.execute = function(command, params, callback) { if (!command || command == 'undefined') { callback && callback (new Error("Invalid API call."), null); return; } // If they didn't enter any params and only a function // Assume there are no params if (typeof params == 'function') { callback = params; params = []; } var self = this; // Grab the packet from the library bgLib.getPacket(command, params, function(err, packet) { if (err) { // If we got a problem, let me hear it return callback && callback(err); } // Else we're going to send it down the wire else { // Get the bytes for the packet packet.getByteArray(function(bArray) { // if (DEBUG) { // console.log("Byte Array to be sent: ", bArray); // } // Send the message self.sendBytes(packet, bArray, callback); }); } }); } Messenger.prototype.sendBytes = function(packet, bArray, callback) { // // Send it along var numSent = this.uart.write(bArray); // If we didn't send every byte, something went wrong // Return immediately if (bArray.length != numSent) { // Not enough bytes sent, somethign went wrong callback && callback(new Error("Not all bytes were sent..."), null); // Add the callback to the packet and set it to waiting } else if (callback) { // Set the callback the packet should respond to packet.callback = callback; // Add a timeout var self = this; packet.timeout = setTimeout(function() { self.commandPacketTimeout.bind(self, packet)(); }, this.commandPacketTimeoutDuration); // Push packet into awaiting queue this.awaitingResponse.push(packet); } } Messenger.prototype.commandPacketTimeout = function(commandPacket) { this.popMatchingResponsePacket(commandPacket, function(err, packet) { if (err) return console.log(err); if (packet) { try { return packet.callback(new Error("Packet Timeout...")); } catch (e) { console.log(e); } } }) } Messenger.prototype.popMatchingResponsePacket = function(parsedPacket, callback) { // Grab the first packet that matches the command and class var matchedPacket; // Iterating through packets waiting response for (var i in this.awaitingResponse) { // Grab the packet var packet = this.awaitingResponse[i]; // If the class and ID are the same, we have a match if (packet.cClass == parsedPacket.cClass && packet.cID == parsedPacket.cID) { // Clear the packet timeout clearTimeout(packet.timeout); // Delete it from the array this.awaitingResponse.splice(i, 1); // Save the command and break the loop matchedPacket = packet; break; } } callback && callback(null, matchedPacket); return matchedPacket; } Messenger.prototype.parseIncomingPackets = function(data) { if (DEBUG) console.log("Just received this data: ", data); var self = this; // Grab the one or more responses from the library var incomingPackets = bgLib.parseIncoming(data, function(err, parsedPackets) { if (DEBUG) console.log("And that turned into ", parsedPackets.length, "packets") if (err){ console.log(err); return; } //For each response for (var i in parsedPackets) { var parsedPacket = parsedPackets[i]; var cClass = parsedPacket.packet.cClass; var cID = parsedPacket.packet.cID; // If it's an event, emit the event // Find the type of packet switch (parsedPacket.packet.mType & 0x80) { // It's an event case 0x80: if (parsedPacket.response) { if (cClass == 0x07 && cID == 0x00) { self.emit("hardwareIOPortStatusChange", parsedPacket.response); } else if (cClass == 0x06 && cID == 0x00) { self.emit("discover", parsedPacket.response); } else if (cClass == 0x00 && cID == 0x00) { self.emit("booted"); } else if (cClass == 0x03 && cID == 0x00) { self.emit("connectionStatus", parsedPacket.response); } else if (cClass == 0x03 && cID == 0x04) { self.emit('disconnectedPeripheral', parsedPacket.response); } else if (cClass == 0x04 && cID == 0x04) { self.emit('foundInformation', parsedPacket.response); } else if (cClass == 0x04 && cID == 0x01) { self.emit('completedProcedure', parsedPacket.response); } else if (cClass == 0x04 && cID == 0x05) { self.emit('readValue', parsedPacket.response); } } break; // It's a response case 0x00: // Find the command that requested it self.popMatchingResponsePacket(parsedPacket.packet, function(err, packet) { // Call the original callback if (packet && packet.callback) packet.callback(err, parsedPacket.response); }); break; default: console.log("Malformed packet returned..."); } } }); } module.exports = Messenger;