generated from thinkode/modelRepository
peripheral optimizations
This commit is contained in:
@@ -3,9 +3,8 @@ package hardware
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"syscall"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
@@ -31,119 +30,63 @@ var (
|
||||
|
||||
// HardwareManager is the class who manages the hardware
|
||||
type HardwareManager struct {
|
||||
drivers map[string]PeripheralDriver // The map of peripherals finders
|
||||
peripherals []Peripheral // The current list of peripherals
|
||||
deviceChangedEvent chan struct{} // The event when the devices list changed
|
||||
ctx context.Context
|
||||
drivers map[string]PeripheralFinder // The map of peripherals finders
|
||||
peripherals []Peripheral // The current list of peripherals
|
||||
peripheralsScanTrigger chan struct{} // Trigger the peripherals scans
|
||||
goWait sync.WaitGroup // Wait for goroutines to terminate
|
||||
}
|
||||
|
||||
// NewHardwareManager creates a new HardwareManager
|
||||
func NewHardwareManager() *HardwareManager {
|
||||
log.Trace().Str("package", "hardware").Msg("Hardware instance created")
|
||||
return &HardwareManager{
|
||||
drivers: make(map[string]PeripheralDriver),
|
||||
peripherals: make([]Peripheral, 0),
|
||||
deviceChangedEvent: make(chan struct{}),
|
||||
drivers: make(map[string]PeripheralFinder),
|
||||
peripherals: make([]Peripheral, 0),
|
||||
peripheralsScanTrigger: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// Start starts to find new peripheral events
|
||||
func (h *HardwareManager) Start(ctx context.Context) error {
|
||||
// Configure wndProc callback
|
||||
cb := windows.NewCallback(h.wndProc)
|
||||
inst := win.GetModuleHandle(nil)
|
||||
|
||||
// Register window class
|
||||
className, err := syscall.UTF16PtrFromString("DMXConnectPeripheralWatcher")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert window class name to UTF16: %w", err)
|
||||
}
|
||||
wc := win.WNDCLASSEX{
|
||||
CbSize: uint32(unsafe.Sizeof(win.WNDCLASSEX{})),
|
||||
HInstance: inst,
|
||||
LpfnWndProc: cb,
|
||||
LpszClassName: className,
|
||||
}
|
||||
if win.RegisterClassEx(&wc) == 0 {
|
||||
return fmt.Errorf("failed to register window class: %w", syscall.GetLastError())
|
||||
}
|
||||
|
||||
// Create hidden window
|
||||
windowName, err := syscall.UTF16PtrFromString("usbevent.exe")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert window name to UTF16: %w", err)
|
||||
}
|
||||
hwnd := win.CreateWindowEx(
|
||||
0,
|
||||
wc.LpszClassName,
|
||||
windowName,
|
||||
win.WS_OVERLAPPEDWINDOW,
|
||||
win.CW_USEDEFAULT,
|
||||
win.CW_USEDEFAULT,
|
||||
100,
|
||||
100,
|
||||
0,
|
||||
0,
|
||||
wc.HInstance,
|
||||
nil,
|
||||
)
|
||||
if hwnd == 0 {
|
||||
return fmt.Errorf("failed to create window: %w", syscall.GetLastError())
|
||||
}
|
||||
|
||||
// Hide and update window
|
||||
win.ShowWindow(hwnd, win.SW_HIDE)
|
||||
win.UpdateWindow(hwnd)
|
||||
|
||||
// Start message loop in a goroutine
|
||||
go messageLoop(ctx, hwnd)
|
||||
|
||||
// To handle the peripheral changed
|
||||
go func() {
|
||||
defer log.Debug().Str("file", "hardware").Msg("peripheral getter goroutine exited")
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-h.deviceChangedEvent:
|
||||
log.Debug().Str("file", "hardware").Msg("peripheral change event, triggering scan...")
|
||||
err := h.Scan(ctx)
|
||||
if err != nil {
|
||||
log.Err(err).Str("file", "hardware").Msg("unable to scan peripherals")
|
||||
}
|
||||
}
|
||||
for finderName, finder := range h.drivers {
|
||||
err := finder.Initialize()
|
||||
if err != nil {
|
||||
log.Err(err).Str("file", "hardware").Str("finderName", finderName).Msg("unable to initialize finder")
|
||||
return err
|
||||
}
|
||||
}()
|
||||
err = finder.Start(ctx)
|
||||
if err != nil {
|
||||
log.Err(err).Str("file", "hardware").Str("finderName", finderName).Msg("unable to start finder")
|
||||
return err
|
||||
}
|
||||
}
|
||||
// n, err := detector.Register()
|
||||
// if err != nil {
|
||||
// log.Err(err).Str("file", "hardware").Msg("error registering the usb event")
|
||||
// }
|
||||
// h.detector = n
|
||||
// // Run the detector
|
||||
// n.Run(ctx)
|
||||
// h.goWait.Add(1)
|
||||
// go func() {
|
||||
// defer h.goWait.Done()
|
||||
// for {
|
||||
// select {
|
||||
// case <-ctx.Done():
|
||||
// return
|
||||
// case <-h.detector.EventChannel:
|
||||
// // Trigger hardware scans
|
||||
// log.Info().Str("file", "hardware").Msg("peripheral change event")
|
||||
// case <-h.peripheralsScanTrigger:
|
||||
// log.Info().Str("file", "hardware").Msg("scan triggered")
|
||||
// }
|
||||
// }
|
||||
// }()
|
||||
return nil
|
||||
}
|
||||
|
||||
func messageLoop(ctx context.Context, hwnd win.HWND) {
|
||||
defer log.Debug().Str("file", "hardware").Msg("Peripheral watcher goroutine exited")
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
win.PostQuitMessage(0) // Gracefully terminate message loop
|
||||
return
|
||||
default:
|
||||
var msg win.MSG
|
||||
result := win.GetMessage(&msg, hwnd, 0, 0)
|
||||
if result > 0 {
|
||||
win.TranslateMessage(&msg)
|
||||
win.DispatchMessage(&msg)
|
||||
} else if result == 0 {
|
||||
log.Warn().Str("file", "hardware").Msg("WM_QUIT message received")
|
||||
return
|
||||
} else {
|
||||
log.Error().Str("file", "hardware").Msg("GetMessage returned an error")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetDriver returns a register driver
|
||||
func (h *HardwareManager) GetDriver(driverName string) (PeripheralDriver, error) {
|
||||
func (h *HardwareManager) GetDriver(driverName string) (PeripheralFinder, error) {
|
||||
driver, exists := h.drivers[driverName]
|
||||
if !exists {
|
||||
log.Error().Str("file", "hardware").Str("driverName", driverName).Msg("unable to get the driver")
|
||||
@@ -154,7 +97,7 @@ func (h *HardwareManager) GetDriver(driverName string) (PeripheralDriver, error)
|
||||
}
|
||||
|
||||
// RegisterDriver registers a new peripherals driver
|
||||
func (h *HardwareManager) RegisterDriver(driver PeripheralDriver) {
|
||||
func (h *HardwareManager) RegisterDriver(driver PeripheralFinder) {
|
||||
h.drivers[driver.GetName()] = driver
|
||||
log.Info().Str("file", "hardware").Str("driverName", driver.GetName()).Msg("driver registered")
|
||||
}
|
||||
@@ -174,41 +117,43 @@ func (h *HardwareManager) GetPeripheral(driverName string, peripheralID string)
|
||||
}
|
||||
|
||||
// Scan scans all the peripherals for the registered finders
|
||||
func (h *HardwareManager) Scan(ctx context.Context) error {
|
||||
if len(h.drivers) == 0 {
|
||||
log.Warn().Str("file", "hardware").Msg("no driver registered")
|
||||
return fmt.Errorf("no driver registered")
|
||||
}
|
||||
for _, driver := range h.drivers {
|
||||
driverCopy := driver
|
||||
go func() {
|
||||
err := driverCopy.Scan(ctx)
|
||||
if err != nil {
|
||||
log.Err(err).Str("file", "hardware").Str("driverName", driverCopy.GetName()).Msg("unable to scan peripheral")
|
||||
return
|
||||
}
|
||||
}()
|
||||
}
|
||||
func (h *HardwareManager) Scan() error {
|
||||
h.peripheralsScanTrigger <- struct{}{}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HardwareManager) wndProc(hwnd windows.HWND, msg uint32, wParam, lParam uintptr) uintptr {
|
||||
log.Trace().Str("file", "hardware").Msg("wndProc triggered")
|
||||
switch msg {
|
||||
case win.WM_DEVICECHANGE:
|
||||
log.Trace().Str("file", "hardware").Uint32("msg", msg).Msg("wndProc triggered")
|
||||
if msg == win.WM_DEVICECHANGE {
|
||||
// Trigger the devices scan when the last DEVICE_CHANGE event is received
|
||||
if debounceTimer != nil {
|
||||
debounceTimer.Stop()
|
||||
log.Trace().Str("file", "hardware").Msg("scan debounce timer stopped")
|
||||
log.Debug().Str("file", "hardware").Msg("scan debounce timer stopped")
|
||||
}
|
||||
debounceTimer = time.AfterFunc(debounceDuration, func() {
|
||||
log.Debug().Str("file", "hardware").Msg("peripheral changed")
|
||||
h.deviceChangedEvent <- struct{}{}
|
||||
h.peripheralsScanTrigger <- struct{}{}
|
||||
})
|
||||
}
|
||||
return win.DefWindowProc(win.HWND(hwnd), msg, wParam, lParam)
|
||||
}
|
||||
|
||||
// Stop stops the hardware manager
|
||||
func (h *HardwareManager) Stop() error {
|
||||
log.Trace().Str("file", "hardware").Msg("closing the hardware manager")
|
||||
// Stop each finder
|
||||
for finderName, finder := range h.drivers {
|
||||
err := finder.Stop()
|
||||
if err != nil {
|
||||
log.Err(err).Str("file", "hardware").Str("finderName", finderName).Msg("unable to stop the finder")
|
||||
}
|
||||
}
|
||||
// Wait for goroutines to finish
|
||||
h.goWait.Wait()
|
||||
log.Info().Str("file", "hardware").Msg("hardware manager stopped")
|
||||
return nil
|
||||
}
|
||||
|
||||
// peripheralsList emits a peripheral event
|
||||
func emitPeripheralsEvents(ctx context.Context, peripheralsList map[string]Peripheral, peripheralEvent PeripheralEvent) {
|
||||
for _, peripheral := range peripheralsList {
|
||||
|
||||
Reference in New Issue
Block a user