Initial commit

This commit is contained in:
PROFERIS - Mi³osz Stocki
2026-07-06 11:34:03 +02:00
commit 67b4eda6aa
12 changed files with 2735 additions and 0 deletions
+139
View File
@@ -0,0 +1,139 @@
/**
* WijiBoard BLE Singleton
* web/js/ble.js
*
* Provides a singleton BLE object with:
* BLE.connect() → connects to device, gets characteristics
* BLE.disconnect() → disconnects
* BLE.write(cmd) → writes ASCII command (write-without-response)
* BLE.isConnected() → boolean
* BLE.on(event, cb) → subscribe to 'connected' | 'disconnected' | 'status'
* BLE.off(event, cb) → unsubscribe
*
* Command characteristic (WRITE_NR):
* S1+<n> → step motor 1 clockwise n steps
* S1-<n> → step motor 1 counter-clockwise n steps
* S2+<n> → step motor 2 clockwise n steps
* S2-<n> → step motor 2 counter-clockwise n steps
* SPD:<n> → set max speed (steps/sec)
* ACC:<n> → set acceleration (steps/sec²)
* HOME → zero both steppers
* POS → request position report
*
* Status characteristic (NOTIFY):
* P:<s1>,<s2> → current step positions for motor 1 & 2
*/
// ── UUIDs must match src/main.cpp exactly ──────────────────────
const SERVICE_UUID = 'a0b1c2d3-e4f5-6789-abcd-ef0123456700';
const CMD_UUID = 'a0b1c2d3-e4f5-6789-abcd-ef0123456701';
const STATUS_UUID = 'a0b1c2d3-e4f5-6789-abcd-ef0123456702';
const DEVICE_NAME = 'WijiBoard';
const BLE = (() => {
// ── Internal state ──────────────────────────────────────────
let device = null;
let server = null;
let cmdChar = null;
let statusChar = null;
const encoder = new TextEncoder();
// ── Tiny event emitter ──────────────────────────────────────
const listeners = {};
function emit(event, ...args) {
(listeners[event] || []).forEach(cb => {
try { cb(...args); } catch (e) { console.error('[BLE] listener error', e); }
});
}
function on(event, cb) {
if (!listeners[event]) listeners[event] = [];
listeners[event].push(cb);
}
function off(event, cb) {
if (!listeners[event]) return;
listeners[event] = listeners[event].filter(fn => fn !== cb);
}
// ── Disconnect handler ──────────────────────────────────────
function onDisconnected() {
console.log('[BLE] Device disconnected');
device = null;
server = null;
cmdChar = null;
statusChar = null;
emit('disconnected');
}
// ── Status notification handler ─────────────────────────────
function onStatusNotification(event) {
const value = new TextDecoder().decode(event.target.value);
emit('status', value.trim());
}
// ── connect() ───────────────────────────────────────────────
async function connect() {
if (!navigator.bluetooth) {
throw new Error('Web Bluetooth API not available. Use Chrome/Edge over HTTPS or localhost.');
}
emit('connecting');
device = await navigator.bluetooth.requestDevice({
filters: [{ name: DEVICE_NAME }],
optionalServices: [SERVICE_UUID],
});
device.addEventListener('gattserverdisconnected', onDisconnected);
server = await device.gatt.connect();
const service = await server.getPrimaryService(SERVICE_UUID);
cmdChar = await service.getCharacteristic(CMD_UUID);
// Status notifications (optional firmware may not have this char yet)
try {
statusChar = await service.getCharacteristic(STATUS_UUID);
await statusChar.startNotifications();
statusChar.addEventListener('characteristicvaluechanged', onStatusNotification);
} catch {
console.warn('[BLE] Status characteristic not available notifications disabled');
}
emit('connected', device.name);
}
// ── disconnect() ────────────────────────────────────────────
async function disconnect() {
if (device?.gatt?.connected) {
device.gatt.disconnect();
}
}
// ── write() ─────────────────────────────────────────────────
async function write(cmd) {
if (!cmdChar) throw new Error('BLE not connected');
await cmdChar.writeValueWithoutResponse(encoder.encode(cmd));
emit('sent', cmd);
}
// ── isConnected() ───────────────────────────────────────────
function isConnected() {
return !!(device?.gatt?.connected && cmdChar);
}
// ── getDeviceName() ─────────────────────────────────────────
function getDeviceName() {
return device?.name ?? null;
}
return {
on, off, connect, disconnect, write, isConnected, getDeviceName,
SERVICE_UUID, CMD_UUID, STATUS_UUID, DEVICE_NAME,
};
})();
export default BLE;