diff --git a/API.md b/API.md index 3f8c051..b3ad98b 100644 --- a/API.md +++ b/API.md @@ -8,7 +8,8 @@ 1. [LED Matrix](#led-matrix) 1. [Magnetometer](#magnetometer) 1. [Temperature](#temperature) -1. [UART](#uart) +1. [UART](#uart) +1. [Event](#event-5) ## Require module @@ -368,3 +369,36 @@ microbit.on('uartData', function(data) { ```javascript microbit.writeUart(data, callback(error)); ``` + +## [Event](https://lancaster-university.github.io/microbit-docs/ble/event-service/) + +### Micro:bit Events + +Events come in two varieties, reflected by the two corresponding characteristics: + +Micro:bit Events emanate from the micro:bit and may be notified to the connected client. + +Client Events emanate from the connected client and may be written to the connected micro:bit + + +### Write event + +```javascript +microbit.writeEvent(id, value, callback); +``` + +### Subscription + +```javascript +microbit.subscribeEvents(id, value, callback(error)); + +microbit.unsubscribeEvent(callback(error)); +``` + +#### Event + +```javascript +microbit.on('event', function(id, value) { + // ... +}); +``` diff --git a/examples/event-listener.js b/examples/event-listener.js new file mode 100644 index 0000000..f023658 --- /dev/null +++ b/examples/event-listener.js @@ -0,0 +1,83 @@ +/* +* Informs micro:bit of interest in events with event ID 9999 and any event value. Logs events as they are received. +* +* Author: Martin Woolley, @bluetooth_mdw +* +* Example: +* +* sudo node event-listener.js +* +* micro:bit hex file must include the Bluetooth Event Service +* +* http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html for hex files and micro:bit info +*/ + +var BBCMicrobit = require('../index'); // or require('bbc-microbit') + +var EVENT_FAMILY = 9999; +var EVENT_VALUE_ANY = 0; +var EVENT_VALUE_1 = 1; + +// search for a micro:bit, to discover a particular micro:bit use: +// BBCMicrobit.discoverById(id, callback); or BBCMicrobit.discoverByAddress(id, callback); +// +// C/C++ code containing the following fragments can be used for testing. +// Pressing button A generates event ID 9999, value 1 +// Pressing button B generates event ID 9999, value 2 +// + +/* +#include "MicroBit.h" +MicroBit uBit; +int EVENT_ID = 9999; + +void onButton(MicroBitEvent e) +{ + if (e.source == MICROBIT_ID_BUTTON_A) { + MicroBitEvent evt(EVENT_ID, 1); + } + if (e.source == MICROBIT_ID_BUTTON_B) { + MicroBitEvent evt(EVENT_ID, 2); + } +} +int main() +{ + // Initialise the micro:bit runtime. + uBit.init(); + uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, onButton); + uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButton); + release_fiber(); +} +*/ + +console.log('Scanning for microbit'); +BBCMicrobit.discover(function(microbit) { + console.log('\tdiscovered microbit: id = %s, address = %s', microbit.id, microbit.address); + + + microbit.on('event', function(id, value) { + console.log('\ton -> micro:bit event received event: %d value: %d', id, value); + }); + + microbit.on('disconnect', function() { + console.log('\tmicrobit disconnected!'); + process.exit(0); + }); + + console.log('connecting to microbit'); + microbit.connectAndSetUp(function() { + console.log('\tconnected to microbit'); + + // Example 1: subscribe to all micro:bit events with ID 9999 and any event value + console.log('subscribing to event family 9999, any event value'); + microbit.subscribeEvents(EVENT_FAMILY, EVENT_VALUE_ANY, function() { + console.log('\tsubscribed to micro:bit events of required type'); + }); + + // Example 2: subscribe to the specific event with ID=9999 and value=0001 only +// console.log('subscribing to event family 9999, event value 0001'); +// microbit.subscribeEvents(EVENT_FAMILY, EVENT_VALUE_1, function() { +// console.log('\tsubscribed to micro:bit events of required type'); +// }); + }); +}); diff --git a/lib/bbc-microbit.js b/lib/bbc-microbit.js index 7af4659..ebb2b97 100644 --- a/lib/bbc-microbit.js +++ b/lib/bbc-microbit.js @@ -7,6 +7,7 @@ var LedService = require('./led-service'); var MagnetometerService = require('./magnetometer-service'); var TemperatureService = require('./temperature-service'); var UartService = require('./uart-service'); +var EventService = require('./event-service'); function BBCMicrobit() { } @@ -30,6 +31,7 @@ NobleDevice.Util.mixin(BBCMicrobit, LedService); NobleDevice.Util.mixin(BBCMicrobit, MagnetometerService); NobleDevice.Util.mixin(BBCMicrobit, TemperatureService); NobleDevice.Util.mixin(BBCMicrobit, UartService); +NobleDevice.Util.mixin(BBCMicrobit, EventService); BBCMicrobit.prototype.toString = function() { return JSON.stringify({ diff --git a/lib/event-service.js b/lib/event-service.js new file mode 100644 index 0000000..7f897cf --- /dev/null +++ b/lib/event-service.js @@ -0,0 +1,60 @@ +var EVENT_SERVICE_SERVICE_UUID = 'e95d93af251d470aa062fa1922dfa9a8'; +var MICROBIT_EVENT_CHARACTERISTIC_UUID = 'e95d9775251d470aa062fa1922dfa9a8'; +var CLIENT_REQUIREMENTS_CHARACTERISTIC_UUID = 'e95d23c4251d470aa062fa1922dfa9a8'; +var CLIENT_EVENT_CHARACTERISTIC_UUID = 'e95d5404251d470aa062fa1922dfa9a8'; + +var EventService = function() { +}; + +EventService.prototype.hasEventService = function() { + return this.hasService(EVENTSERVICE_SERVICE_UUID); +}; + +EventService.prototype.onEvent = function(data) { + if (data.length !== 4) { + return; + } + + var id = data.readInt16LE(0); + var value = data.readInt16LE(2); + + this.emit('event', id, value); +}; + +EventService.prototype.subscribeEvents = function(id, value, callback) { + // specifying which events we want to be notified about + this._writeClientEventRequirements(id, value, callback); + + if (!this._eventSubscribed) { + this.onEventBinded = this.onEvent.bind(this); + + this.subscribeCharacteristic(EVENT_SERVICE_SERVICE_UUID, MICROBIT_EVENT_CHARACTERISTIC_UUID, this.onEventBinded); + + this._eventSubscribed = true; + } +}; + +EventService.prototype.unsubscribeEvent = function(callback) { + // allow this event if not previously explicitly subscribed through a call to subscribeEvents because the micro:bit may have persisted the + // client characteristic configuration descriptor state from a previous "session" + this.unsubscribeCharacteristic(EVENT_SERVICE_SERVICE_UUID, MICROBIT_EVENT_CHARACTERISTIC_UUID, this.onEventBinded, callback); + + this._eventSubscribed = false; +}; + +EventService.prototype._writeClientEventRequirements = function(id, value, callback) { + var data = new Buffer(4); + + data.writeUInt16LE(id, 0); + data.writeUInt16LE(value, 2); + + this.writeDataCharacteristic(EVENT_SERVICE_SERVICE_UUID, CLIENT_REQUIREMENTS_CHARACTERISTIC_UUID, data, callback); +}; + +EventService.prototype.writeEvent = function(id, value, callback) { + var data = id << 16 | value; + + this.writeUInt32LECharacteristic(EVENT_SERVICE_SERVICE_UUID, CLIENT_EVENT_CHARACTERISTIC_UUID, data, callback); +}; + +module.exports = EventService;