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,