feature: Get sensor data reading working

This commit is contained in:
Tera << 8 2025-06-24 16:30:16 -04:00
parent ad3045fc29
commit 243d595a35
Signed by: imterah
GPG key ID: 8FA7DD57BA6CEA37
11 changed files with 413 additions and 147 deletions

13
.zed/settings.json Normal file
View file

@ -0,0 +1,13 @@
// Folder-specific settings
//
// For a full list of overridable settings, and general information on folder-specific settings,
// see the documentation: https://zed.dev/docs/configuring-zed#settings-files
{
"lsp": {
"gopls": {
"initialization_options": {
"buildFlags": ["-tags=xreal,noaudio,drm,drm_leasing,drm_disable_input"]
}
}
}
}

View file

@ -1,6 +1,6 @@
APP_DIR := ./app
OUTPUT := uxr
TAGS := xreal drm drm_leasing drm_disable_input
TAGS := xreal noaudio drm drm_leasing drm_disable_input
.PHONY: all build clean

View file

@ -132,7 +132,7 @@ func mainEntrypoint(context.Context, *cli.Command) error {
},
})
displayMetadataBlock := make([]*renderer.EvdiDisplayMetadata, *config.DisplayConfig.Count)
evdiCards := make([]*renderer.EvdiDisplayMetadata, *config.DisplayConfig.Count)
for currentDisplay := range *config.DisplayConfig.Count {
openedDevice, err := libevdi.Open(nil)
@ -156,13 +156,16 @@ func mainEntrypoint(context.Context, *cli.Command) error {
displayBuffer := openedDevice.CreateBuffer(displayMetadata.MaxWidth, displayMetadata.MaxHeight, 4, displayRect)
displayMetadataBlock[currentDisplay] = &renderer.EvdiDisplayMetadata{
evdiCards[currentDisplay] = &renderer.EvdiDisplayMetadata{
EvdiNode: openedDevice,
Rect: displayRect,
Buffer: displayBuffer,
}
}
log.Info("Initialized displays. Entering rendering loop")
renderer.EnterRenderLoop(config, displayMetadata, evdiCards)
atexit.Exit(0)
return nil
}

51
app/renderer/renderer.go Normal file
View file

@ -0,0 +1,51 @@
package renderer
import (
"time"
libconfig "git.terah.dev/UnrealXR/unrealxr/app/config"
"git.terah.dev/UnrealXR/unrealxr/app/edidtools"
"git.terah.dev/UnrealXR/unrealxr/ardriver"
arcommons "git.terah.dev/UnrealXR/unrealxr/ardriver/commons"
"github.com/charmbracelet/log"
"github.com/tebeka/atexit"
)
func EnterRenderLoop(config *libconfig.Config, displayMetadata *edidtools.DisplayMetadata, evdiCards []*EvdiDisplayMetadata) {
log.Info("Initializing AR driver")
headset, err := ardriver.GetDevice()
if err != nil {
log.Errorf("Failed to get device: %s", err.Error())
atexit.Exit(1)
}
log.Info("Initialized")
var pitch float32
var yaw float32
var roll float32
arEventListner := &arcommons.AREventListener{
PitchCallback: func(newPitch float32) {
pitch = newPitch
},
YawCallback: func(newYaw float32) {
yaw = newYaw
},
RollCallback: func(newRoll float32) {
roll = newRoll
},
}
if headset.IsPollingLibrary() {
log.Error("Connected AR headset requires polling but polling is not implemented in the renderer!")
atexit.Exit(1)
}
headset.RegisterEventListeners(arEventListner)
for {
log.Debugf("pitch: %f, yaw: %f, roll: %f", pitch, yaw, roll)
time.Sleep(10 * time.Millisecond)
}
}

View file

@ -1 +1,23 @@
package ardriver
import (
"fmt"
"git.terah.dev/UnrealXR/unrealxr/ardriver/commons"
"git.terah.dev/UnrealXR/unrealxr/ardriver/xreal"
)
func GetDevice() (commons.ARDevice, error) {
if xreal.IsXrealEnabled {
device, err := xreal.New()
if err != nil {
fmt.Printf("failed to initialize xreal device: %w\n", err)
return nil, err
}
return device, nil
}
return nil, fmt.Errorf("failed to initialize any device")
}

View file

@ -25,8 +25,8 @@
#include "device_imu.h"
#include "device.h"
#include <Fusion/FusionAxes.h>
#include <Fusion/FusionMath.h>
#include <FusionAxes.h>
#include <FusionMath.h>
#include <float.h>
#include <json-c/json_object.h>
#include <json-c/json_types.h>
@ -35,7 +35,7 @@
#include <stdlib.h>
#include <string.h>
#include <Fusion/Fusion.h>
#include <Fusion.h>
#include <json-c/json.h>
#include <hidapi/hidapi.h>

7
ardriver/xreal/go_ffi.c Normal file
View file

@ -0,0 +1,7 @@
#include "device_imu.h"
extern void goIMUEventHandler(uint64_t, device_imu_event_type, device_imu_ahrs_type*);
void imuEventHandler(uint64_t timestamp, device_imu_event_type event, const device_imu_ahrs_type* ahrs) {
goIMUEventHandler(timestamp, event, (device_imu_ahrs_type*)ahrs);
}

3
ardriver/xreal/go_ffi.h Normal file
View file

@ -0,0 +1,3 @@
#include "device_imu.h"
extern void goIMUEventHandler(uint64_t, device_imu_event_type, device_imu_ahrs_type*);
void imuEventHandler(uint64_t timestamp, device_imu_event_type event, const device_imu_ahrs_type* ahrs);

View file

@ -3,10 +3,132 @@
package xreal
// #include "evdi_lib.h"
// #include "go_ffi.h"
// #cgo CFLAGS: -w
// #cgo CFLAGS: -w -I./Fusion/
// #cgo pkg-config: json-c libusb-1.0 hidapi-libusb
// #include "go_ffi.h"
// #include "device.h"
// #include "device_imu.h"
// #include "device_mcu.h"
import "C"
import (
"fmt"
"sync"
"time"
var IsXrealEnabled = true
"git.terah.dev/UnrealXR/unrealxr/ardriver/commons"
)
var (
IsXrealEnabled = true
deviceEventHandlerMutex = sync.Mutex{}
deviceEventListener *commons.AREventListener
)
//export goIMUEventHandler
func goIMUEventHandler(_ C.uint64_t, event_type C.device_imu_event_type, ahrs *C.struct_device_imu_ahrs_t) {
if deviceEventListener == nil {
return
}
if event_type != C.DEVICE_IMU_EVENT_UPDATE {
return
}
orientation := C.device_imu_get_orientation(ahrs)
euler := C.device_imu_get_euler(orientation)
deviceEventListener.PitchCallback(float32(euler.pitch))
deviceEventListener.RollCallback(float32(euler.roll))
deviceEventListener.YawCallback(float32(euler.yaw))
}
// Implements commons.ARDevice
type XrealDevice struct {
eventListener *commons.AREventListener
imuDevice *C.struct_device_imu_t
deviceIsOpen bool
}
func (device *XrealDevice) Initialize() error {
if device.deviceIsOpen {
return fmt.Errorf("device is already open")
}
device.imuDevice = &C.struct_device_imu_t{}
// (*[0]byte) is a FUBAR way to cast a pointer to a function, but unsafe.Pointer doesn't work:
// cannot use unsafe.Pointer(_Cgo_ptr(_Cfpvar_fp_imuEventHandler)) (value of type unsafe.Pointer) as *[0]byte value in variable declaration
if C.DEVICE_IMU_ERROR_NO_ERROR != C.device_imu_open(device.imuDevice, (*[0]byte)(C.imuEventHandler)) {
return fmt.Errorf("failed to open IMU device")
}
C.device_imu_clear(device.imuDevice)
C.device_imu_calibrate(device.imuDevice, 1000, true, true, false)
device.deviceIsOpen = true
// let's hope this doesn't cause race conditions
go func() {
for device.eventListener == nil {
time.Sleep(time.Millisecond * 10)
}
for {
if !device.deviceIsOpen {
break
}
// I'm sorry.
deviceEventHandlerMutex.Lock()
deviceEventListener = device.eventListener
status := C.device_imu_read(device.imuDevice, -1)
deviceEventHandlerMutex.Unlock()
if status != C.DEVICE_IMU_ERROR_NO_ERROR {
break
}
}
device.deviceIsOpen = false
C.device_imu_close(device.imuDevice)
}()
return nil
}
func (device *XrealDevice) End() error {
if !device.deviceIsOpen {
return fmt.Errorf("device is not open")
}
C.device_imu_close(device.imuDevice)
device.deviceIsOpen = false
return nil
}
func (device *XrealDevice) IsPollingLibrary() bool {
return false
}
func (device *XrealDevice) IsEventBasedLibrary() bool {
return true
}
func (device *XrealDevice) Poll() error {
return fmt.Errorf("not supported")
}
func (device *XrealDevice) RegisterEventListeners(listener *commons.AREventListener) {
device.eventListener = listener
}
func New() (*XrealDevice, error) {
device := &XrealDevice{}
err := device.Initialize()
if err != nil {
return nil, err
}
return device, nil
}

View file

@ -0,0 +1,7 @@
//go:build xreal && !xreal_debug_logging
// +build xreal,!xreal_debug_logging
package xreal
// #cgo CFLAGS: -DNDEBUG
import "C"

View file

@ -3,4 +3,42 @@
package xreal
import (
"fmt"
"git.terah.dev/UnrealXR/unrealxr/ardriver/commons"
)
var IsXrealEnabled = false
// Implements commons.ARDevice
type XrealDevice struct {
}
func (device *XrealDevice) Initialize() error {
return fmt.Errorf("xreal is not enabled")
}
func (device *XrealDevice) End() error {
return fmt.Errorf("xreal is not enabled")
}
func (device *XrealDevice) IsPollingLibrary() bool {
return false
}
func (device *XrealDevice) IsEventBasedLibrary() bool {
return false
}
func (device *XrealDevice) Poll() error {
return fmt.Errorf("xreal is not enabled")
}
func (device *XrealDevice) RegisterEventListeners(*commons.AREventListener) error {
return fmt.Errorf("xreal is not enabled")
}
func New() (*XrealDevice, error) {
return nil, fmt.Errorf("xreal is not enabled")
}