diff --git a/README.md b/README.md index b64483f..42f005c 100644 --- a/README.md +++ b/README.md @@ -2,43 +2,52 @@ work in progress; webxr support for xreal devices -Read the history of these projects: +> WebXR Bindings and Test Utilities / Getting-Started Example(s) Basis for NPM package -> https://jakedownsdev.substack.com/p/open-sourcing-nreal-air-development?utm_source=profile&utm_medium=reader2 - -based on combined effort of: - -### Community Open Source Xreal Drivers: - -- [Windows](https://github.com/MSmithDev/AirAPI_Windows) - .dll -- [Android](https://github.com/SARankDirector-Minecraft/XR-android-driver) - .aar -- [Linux](https://gitlab.com/TheJackiMonster/nrealAirLinuxDriver) - .so -- [Mac](https://gitlab.com/DanBurkhardt/nrealAirLinuxDriver/-/tree/main) - .dylib -- [WebXR](https://github.com/jakedowns/xreal-webxr) - WebXR Bindings and Test Utilities / Getting-Started Example(s) Basis for NPM package -- [Rust](https://github.com/badicsalex/ar-drivers-rs) - Cross-Platform Rust Library -- [XR Gaming Decky Plugin](https://github.com/wheaney/decky-XRGaming) - XR Gaming Decky Plugin -- [XRLinux](https://github.com/wheaney/XRLinuxDriver) -- [OpenVR-xrealAirGlassesHMD](https://github.com/wheaney/OpenVR-xrealAirGlassesHMD) - OpenVR driver for xReal Air Glasses as a HMD +🙌 🥽 💪 based on combined effort of the Xreal Open Source Community: ### Projects using Open Source Xreal Drivers - [OpenGL demo program](https://github.com/abls/real-air) -- [kassandra](https://www.youtube.com/watch?v=7pH2VvUTZIQ) Kassandra: AR for all Macs with Nreal Air, is now in Public Beta -- [breezy desktop](https://github.com/wheaney/breezy-desktop) - Linux -- [cozy desk](https://cozydesk.space/download/) - Mac -- [PhoenixHeadTracker](https://github.com/iVideoGameBoss/PhoenixHeadTracker/releases) - Windows -- [Monado - xreal support](https://gitlab.freedesktop.org/monado/monado/-/tree/main/src/xrt/drivers/nreal_air) - Linux + OpenXR (via [TheJackiMonster](https://gitlab.com/TheJackiMonster)) +- [kassandra](https://www.youtube.com/watch?v=7pH2VvUTZIQ) 🍎 Mac +- [breezy desktop](https://github.com/wheaney/breezy-desktop) 🐧 Linux +- [cozy desk](https://cozydesk.space/download/) 🍏 Mac +- [PhoenixHeadTracker](https://github.com/iVideoGameBoss/PhoenixHeadTracker/releases) 🖼️ Windows +- [Monado - xreal support](https://gitlab.freedesktop.org/monado/monado/-/tree/main/src/xrt/drivers/nreal_air) 🐧 Linux + OpenXR + +### Xreal Open Source Community Drivers: + +- [WebXR](https://github.com/jakedowns/xreal-webxr) +- [Windows](https://github.com/MSmithDev/AirAPI_Windows) +- [Android](https://github.com/SARankDirector-Minecraft/XR-android-driver) +- [Linux](https://gitlab.com/TheJackiMonster/nrealAirLinuxDriver) +- [Mac](https://gitlab.com/DanBurkhardt/nrealAirLinuxDriver/-/tree/main) +- [Rust](https://github.com/badicsalex/ar-drivers-rs) +- [XR Gaming Decky Plugin](https://github.com/wheaney/decky-XRGaming) +- [XR Linux Driver](https://github.com/wheaney/XRLinuxDriver) +- [OpenVR-xrealAirGlassesHMD](https://github.com/wheaney/OpenVR-xrealAirGlassesHMD) ### Utilities -- [Unofficial Firmware Mirror](https://air.msmithdev.com/) - Web Firmware Updater Mirror -- [IMU Inspector](https://github.com/abls/imu-inspector) +- 🪞 [Unofficial Firmware Archive Mirror](https://air.msmithdev.com/) +- 🔍 [IMU Inspector](https://github.com/abls/imu-inspector) +- 📊 [Real Utilities](https://github.com/edwatt/real_utilities/) +### Special Thanks! +- [Tobias Frisch, TheJackiMonster](https://gitlab.com/TheJackiMonster) +- [Matt Smith, MSmithDev](https://github.com/MSmithDev) +- [Ed Watt](https://github.com/edwatt) +- [Andy, abls, noot](https://github.com/abls) +- [Wayne Heaney, wheaney](https://github.com/wheaney) +- [Alex Badics, badicsalex](https://github.com/badicsalex) +- [SARankDirector-Minecraft](https://github.com/SARankDirector-Minecraft) ### Roadmap -- [OpenXR](#coming-soon) # coming soon -- [CloudXR](#on-hold) # on hold +- 🌐 🥽 [OpenXR](#coming-soon) # coming soon +- ☁️ 🥽 [CloudXR](#on-hold) # on hold +### Read the history of this project: +🤩 [Open-Sourcing Nreal Air Development - SubStack](https://jakedownsdev.substack.com/p/open-sourcing-nreal-air-development?utm_source=profile&utm_medium=reader2) \ No newline at end of file diff --git a/index_old.html b/index_old.html index 46b2b5d..e737afd 100644 --- a/index_old.html +++ b/index_old.html @@ -88,10 +88,10 @@
current brightness: ?

-
-
-
-
+ + + +
@@ -486,7 +486,7 @@ window.sparkline_elements = []; window.onload = async () => { - + /* for(var i = 0; i<41; i++){ let child = document.createElement('div'); child.classList.add('bar'); @@ -524,6 +524,7 @@ document.getElementById('sparklines').append(_sl_wrapper) } + */ if (!Manager?.hidSupported()) { document.getElementById('noSupportHid').style.display = "block"; diff --git a/js_air/glasses.js b/js_air/glasses.js index 19f6763..85af986 100644 --- a/js_air/glasses.js +++ b/js_air/glasses.js @@ -131,6 +131,10 @@ window.logPackets = () => { // } export default class Glasses extends EventTarget { + + /* RepeatingDeviceReportPoll */ + imu_poller_instance = null; + constructor(device) { console.log('constructing'); super(); @@ -138,6 +142,25 @@ export default class Glasses extends EventTarget { this._interestMsg = []; this._reports = new Map(); this._captures = []; + + // creates it, but doesn't start it... + this.imu_poller_instance = new RepeatingDeviceReportPoll({ + interval: 100, + callback: async ()=>{ + this.sendReportTimeout(Protocol.MESSAGES.R_IMU_DATA, [0x40]).then((report)=>{ + if(report){ + console.log('got report',report) + }else{ + console.log('no report') + } + }).catch((e)=>{ + console.error('error sending report',e) + }).finally(()=>{ + //console.log('finally') + }); + } + }); + // set input listener device.oninputreport = this._handleInputReport.bind(this); @@ -153,6 +176,14 @@ export default class Glasses extends EventTarget { // this.renderSparklines(); } + startIMUPolling(){ + this.imu_poller_instance.start(); + } + + stopIMUPolling(){ + this.imu_poller_instance.end(); + } + renderSparklines(){ if(!window.imu_output){ return; @@ -229,7 +260,7 @@ export default class Glasses extends EventTarget { } if(report.msgId === 0){ - // console.log(report.payload.length, report.status) + console.log(report.payload.length, report.status) imu_report_current++; @@ -430,4 +461,36 @@ export default class Glasses extends EventTarget { toString() { return ``; } + + +} + +class RepeatingDeviceReportPoll { + timer = null; + constructor(opts){ + opts = opts || {}; + opts = { + interval: 100, + callback: ()=>{}, // this is the function that will be called + ...opts + } + this.opts = opts; + + } + + start(){ + this.ended = false; + this.timer = setInterval(() => { + if(this.ended){ + clearInterval(this.timer) + }else{ + this.opts.callback() + } + },this.opts.interval) + } + + end(){ + // stop the timer on next tick + this.ended = true; + } } \ No newline at end of file diff --git a/js_air/manager.js b/js_air/manager.js index 773f9f8..2bb1320 100644 --- a/js_air/manager.js +++ b/js_air/manager.js @@ -513,7 +513,11 @@ export async function startIMU() { if(!glasses){ return Promise.reject('no device connected') } - return glasses.sendReportTimeout(Protocol.MESSAGES.W_TOGGLE_IMU, [1]) + + // kick off polling + glasses.startIMUPolling(); + + return glasses.sendReportTimeout(Protocol.MESSAGES.W_TOGGLE_IMU, [0x1]) .then(report => { console.warn('startIMU -> report',report); if (reportSuccess(report)){ @@ -529,7 +533,7 @@ export async function stopIMU() { return 'no device connected' } // arg 2: 0 is what turns "off" the stream - return glasses.sendReportTimeout(Protocol.MESSAGES.W_TOGGLE_IMU, [0]) + return glasses.sendReportTimeout(Protocol.MESSAGES.W_TOGGLE_IMU, [0x0]) .then(report => { console.warn('stopIMU -> report',report); if (reportSuccess(report)){ diff --git a/js_air/protocol.js b/js_air/protocol.js index d144302..aca4a2b 100644 --- a/js_air/protocol.js +++ b/js_air/protocol.js @@ -12,6 +12,72 @@ export const NREAL_VENDOR_ID = 0x3318; export const BOOT_PRODUCT_ID = 0x0423; export const IMU_TIMEOUT = 250; +export const ERRORS = { + DEVICE3_ERROR_NO_ERROR: 0, + DEVICE3_ERROR_NO_DEVICE: 1, + DEVICE3_ERROR_NO_HANDLE: 2, + DEVICE3_ERROR_NO_ALLOCATION: 3, + DEVICE3_ERROR_WRONG_SIZE: 4, + DEVICE3_ERROR_FILE_NOT_OPEN: 5, + DEVICE3_ERROR_FILE_NOT_CLOSED: 6, + DEVICE3_ERROR_LOADING_FAILED: 7, + DEVICE3_ERROR_SAVING_FAILED: 8, + DEVICE3_ERROR_UNPLUGGED: 9, + DEVICE3_ERROR_UNEXPECTED: 10, + DEVICE3_ERROR_WRONG_SIGNATURE: 11, + DEVICE3_ERROR_INVALID_VALUE: 12, + DEVICE3_ERROR_NOT_INITIALIZED: 13, + DEVICE3_ERROR_PAYLOAD_FAILED: 14, + DEVICE3_ERROR_UNKNOWN: 15, +} + +class Device3Packet { + /* + uint8_t signature [2]; + uint8_t temperature [2]; + uint64_t timestamp; + uint8_t angular_multiplier [2]; + uint8_t angular_divisor [4]; + uint8_t angular_velocity_x [3]; + uint8_t angular_velocity_y [3]; + uint8_t angular_velocity_z [3]; + uint8_t acceleration_multiplier [2]; + uint8_t acceleration_divisor [4]; + uint8_t acceleration_x [3]; + uint8_t acceleration_y [3]; + uint8_t acceleration_z [3]; + uint8_t magnetic_multiplier [2]; + uint8_t magnetic_divisor [4]; + uint8_t magnetic_x [2]; + uint8_t magnetic_y [2]; + uint8_t magnetic_z [2]; + uint32_t checksum; + uint8_t _padding [6]; + */ + constructor() { + this.signature = new Uint8Array(2); + this.temperature = new Uint8Array(2); + this.timestamp = new Uint8Array(8); + this.angular_multiplier = new Uint8Array(2); + this.angular_divisor = new Uint8Array(4); + this.angular_velocity_x = new Uint8Array(3); + this.angular_velocity_y = new Uint8Array(3); + this.angular_velocity_z = new Uint8Array(3); + this.acceleration_multiplier = new Uint8Array(2); + this.acceleration_divisor = new Uint8Array(4); + this.acceleration_x = new Uint8Array(3); + this.acceleration_y = new Uint8Array(3); + this.acceleration_z = new Uint8Array(3); + this.magnetic_multiplier = new Uint8Array(2); + this.magnetic_divisor = new Uint8Array(4); + this.magnetic_x = new Uint8Array(2); + this.magnetic_y = new Uint8Array(2); + this.magnetic_z = new Uint8Array(2); + this.checksum = new Uint8Array(4); + this._padding = new Uint8Array(6); + } +} + export const MESSAGES = { R_MCU_APP_FW_VERSION: 0x26,//MCU APP FW version. @@ -22,6 +88,9 @@ export const MESSAGES = { W_ACTIVATION_TIME: 0x2A,//Write activation time W_SLEEP_TIME: 0x1E,//Write unsleep time + R_IMU_DATA: 0x80,//IMU data + UNKNOWN_40: 0x40,//Unknown + W_TOGGLE_IMU: 0x19, W_CANCEL_ACTIVATION: 0x19,