aboutsummaryrefslogtreecommitdiff
path: root/src/js/uBit.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/uBit.js')
-rw-r--r--src/js/uBit.js142
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);
+}