diff options
Diffstat (limited to 'src/js/uBit.js')
-rw-r--r-- | src/js/uBit.js | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/js/uBit.js b/src/js/uBit.js new file mode 100644 index 0000000..0275ff9 --- /dev/null +++ b/src/js/uBit.js @@ -0,0 +1,142 @@ +/* + * This code is written with a lot of help from these resources: + * https://github.com/antefact/microBit.js/blob/master/src/microBit.js + * https://gist.github.com/kotobuki/7c67f8b9361e08930da1a5cfcfb0653f + * https://lancaster-university.github.io/microbit-docs/resources/bluetooth/bluetooth_profile.html + */ +const UART_SERVICE_UUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e"; +/* Used for reading UART data from micro bit */ +const UART_TX_CHARACTERISTIC_UUID = "6e400002-b5a3-f393-e0a9-e50e24dcca9e"; +/* Used for writing UART data to micro bit */ +const UART_RX_CHARACTERISTIC_UUID = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"; +/* The event service characteristic (which extends the uBit message bus over bluetooth) */ +const EVENT_SERVICE_CHARACTERISTIC_UUID = "e95d93af-251d-470a-a062-fa1922dfa9a8"; +/* This should be read once connected, as the ubit will advertise which events it wants to subscribe to */ +const UBIT_REQUIREMENT_CHARACTERISTIC_UUID = "e95db84c-251d-470a-a062-fa1922dfa9a8"; +/* The characteristic where we should write the events we wish to be informed of from the microbit */ +const CLIENTREQUIREMENTS_CHARACTERISTIC_UUID = "e95d23c4-251d-470a-a062-fa1922dfa9a8" +/* The characteristic used for reading EventService messages */ +const UBITEVENT_CHARACTERISTIC_UUID = "e95d9775-251d-470a-a062-fa1922dfa9a8"; +/* The characteristic used for writing EventService messages */ +const CLIENTEVENT_CHARACTERISTIC_UUID = "e95d5404-251d-470a-a062-fa1922dfa9a8"; + +/* This table is retrieved from this site: + * https://github.com/lancaster-university/microbit-dal/blob/master/inc/bluetooth/MESEvents.h */ +export const MESEvents = { + MES_DPAD_CONTROLLER_ID: 1104, + MES_DPAD_BUTTON_A_DOWN: 1, + MES_DPAD_BUTTON_A_UP: 2, + MES_DPAD_BUTTON_B_DOWN: 3, + MES_DPAD_BUTTON_B_UP: 4, + MES_DPAD_BUTTON_C_DOWN: 5, + MES_DPAD_BUTTON_C_UP: 6, + MES_DPAD_BUTTON_D_DOWN: 7, + MES_DPAD_BUTTON_D_UP: 8, + MES_DPAD_BUTTON_1_DOWN: 9, + MES_DPAD_BUTTON_1_UP: 10, + MES_DPAD_BUTTON_2_DOWN: 11, + MES_DPAD_BUTTON_2_UP: 12, + MES_DPAD_BUTTON_3_DOWN: 13, + MES_DPAD_BUTTON_3_UP: 14, + MES_DPAD_BUTTON_4_DOWN: 15, + MES_DPAD_BUTTON_4_UP: 16 +} + +class BluetoothService { + SERVICE_UUID = null; +} + +class EventService extends BluetoothService { + static SERVICE_UUID = EVENT_SERVICE_CHARACTERISTIC_UUID; + service; + + constructor(service, ubitEvent) { + super(); + this.service = service; + this.ubitEvent = ubitEvent; + console.log("EventService initialized."); + } + + sendEvent(event_type, event_value) { + this.ubitEvent.writeValue( + new Uint16Array([event_type, event_value]) + ); + } + + static async getService(gattServer) { + console.debug("Getting EventService"); + let service = await gattServer.getPrimaryService(EventService.SERVICE_UUID); + console.debug("Getting UBitevent characteristic"); + let ubitEventCharacteristic = await service.getCharacteristic(CLIENTEVENT_CHARACTERISTIC_UUID); + return new EventService(service, ubitEventCharacteristic); + } +} + +export class uBitBLE { + eventService; + device; + + constructor() { + this.onConnectCallback = function() {}; + this.onDisconnectCallback = function() {}; + } + + onConnect(callbackFunction) { + this.onConnectCallback = callbackFunction; + } + + onDisconnect(callbackFunction) { + this.onDisconnectCallback = callbackFunction; + } + + isConnected() { + if (this.device) { + return this.device.gatt.connected; + } else { + return false; + } + } + + disconnect() { + if (this.isConnected()) { + this.device.gatt.disconnect(); + } + } + + async searchDevice() { + this.device = await navigator.bluetooth.requestDevice({ + filters: [{namePrefix: "BBC micro:bit"}], + optionalServices: [EVENT_SERVICE_CHARACTERISTIC_UUID] + }); + this.device.addEventListener('gattserverdisconnected', this.onDisconnectCallback); + console.log("Connected to new device", this.device.name, this.device.id); + + console.debug("Connection to GATT server..."); + const server = await this.device.gatt.connect() + + this.onConnectCallback(); + console.debug("Getting services..."); + + const eventService = await EventService.getService(server); + this.eventService = eventService; + } + +} + +function getSupportedProperties(characteristic) { + let supportedProperties = []; + for (const p in characteristic.properties) { + if (characteristic.properties[p] === true) { + supportedProperties.push(p.toUpperCase()); + } + } + return '[' + supportedProperties.join(', ') + ']'; +} + +function eventByteArrayToString(event) { + let receivedData = []; + for (var i = 0; i < event.target.value.byteLength; i++) { + receivedData[i] = event.target.value.getUint8(i); + } + return String.fromCharCode.apply(null, receivedData); +} |