feature: Get sensor data reading working
This commit is contained in:
parent
ad3045fc29
commit
243d595a35
11 changed files with 413 additions and 147 deletions
13
.zed/settings.json
Normal file
13
.zed/settings.json
Normal 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"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
Makefile
2
Makefile
|
@ -1,6 +1,6 @@
|
||||||
APP_DIR := ./app
|
APP_DIR := ./app
|
||||||
OUTPUT := uxr
|
OUTPUT := uxr
|
||||||
TAGS := xreal drm drm_leasing drm_disable_input
|
TAGS := xreal noaudio drm drm_leasing drm_disable_input
|
||||||
|
|
||||||
.PHONY: all build clean
|
.PHONY: all build clean
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
for currentDisplay := range *config.DisplayConfig.Count {
|
||||||
openedDevice, err := libevdi.Open(nil)
|
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)
|
displayBuffer := openedDevice.CreateBuffer(displayMetadata.MaxWidth, displayMetadata.MaxHeight, 4, displayRect)
|
||||||
|
|
||||||
displayMetadataBlock[currentDisplay] = &renderer.EvdiDisplayMetadata{
|
evdiCards[currentDisplay] = &renderer.EvdiDisplayMetadata{
|
||||||
EvdiNode: openedDevice,
|
EvdiNode: openedDevice,
|
||||||
Rect: displayRect,
|
Rect: displayRect,
|
||||||
Buffer: displayBuffer,
|
Buffer: displayBuffer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Info("Initialized displays. Entering rendering loop")
|
||||||
|
renderer.EnterRenderLoop(config, displayMetadata, evdiCards)
|
||||||
|
|
||||||
atexit.Exit(0)
|
atexit.Exit(0)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
51
app/renderer/renderer.go
Normal file
51
app/renderer/renderer.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +1,23 @@
|
||||||
package ardriver
|
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")
|
||||||
|
}
|
||||||
|
|
|
@ -25,8 +25,8 @@
|
||||||
#include "device_imu.h"
|
#include "device_imu.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
|
||||||
#include <Fusion/FusionAxes.h>
|
#include <FusionAxes.h>
|
||||||
#include <Fusion/FusionMath.h>
|
#include <FusionMath.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include <json-c/json_object.h>
|
#include <json-c/json_object.h>
|
||||||
#include <json-c/json_types.h>
|
#include <json-c/json_types.h>
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <Fusion/Fusion.h>
|
#include <Fusion.h>
|
||||||
#include <json-c/json.h>
|
#include <json-c/json.h>
|
||||||
|
|
||||||
#include <hidapi/hidapi.h>
|
#include <hidapi/hidapi.h>
|
||||||
|
|
7
ardriver/xreal/go_ffi.c
Normal file
7
ardriver/xreal/go_ffi.c
Normal 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
3
ardriver/xreal/go_ffi.h
Normal 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);
|
|
@ -3,10 +3,132 @@
|
||||||
|
|
||||||
package xreal
|
package xreal
|
||||||
|
|
||||||
// #include "evdi_lib.h"
|
// #cgo CFLAGS: -w -I./Fusion/
|
||||||
// #include "go_ffi.h"
|
|
||||||
// #cgo CFLAGS: -w
|
|
||||||
// #cgo pkg-config: json-c libusb-1.0 hidapi-libusb
|
// #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 "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
|
||||||
|
}
|
||||||
|
|
7
ardriver/xreal/xreal_debug_logging.go
Normal file
7
ardriver/xreal/xreal_debug_logging.go
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
//go:build xreal && !xreal_debug_logging
|
||||||
|
// +build xreal,!xreal_debug_logging
|
||||||
|
|
||||||
|
package xreal
|
||||||
|
|
||||||
|
// #cgo CFLAGS: -DNDEBUG
|
||||||
|
import "C"
|
|
@ -3,4 +3,42 @@
|
||||||
|
|
||||||
package xreal
|
package xreal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.terah.dev/UnrealXR/unrealxr/ardriver/commons"
|
||||||
|
)
|
||||||
|
|
||||||
var IsXrealEnabled = false
|
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")
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue