Files
dmxconnect/hardware/hardware.go

152 lines
5.3 KiB
Go

package hardware
import (
"context"
"fmt"
"sync"
"time"
"github.com/rs/zerolog/log"
"github.com/wailsapp/wails/v2/pkg/runtime"
)
// PeripheralEvent is trigger by the finders when the scan is complete
type PeripheralEvent string
const (
// PeripheralArrival is triggerd when a peripheral has been connected to the system
PeripheralArrival PeripheralEvent = "PERIPHERAL_ARRIVAL"
// PeripheralRemoval is triggered when a peripheral has been disconnected from the system
PeripheralRemoval PeripheralEvent = "PERIPHERAL_REMOVAL"
// debounceDuration = 500 * time.Millisecond
)
var (
debounceTimer *time.Timer
)
// HardwareManager is the class who manages the hardware
type HardwareManager struct {
finders 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{
finders: 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 {
for finderName, finder := range h.finders {
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
}
}
h.goWait.Add(1)
go func() {
defer h.goWait.Done()
for {
select {
case <-ctx.Done():
return
case <-h.peripheralsScanTrigger:
for finderName, finder := range h.finders {
log.Trace().Str("file", "hardware").Str("finderName", finderName).Msg("force a finder to scan peripherals")
finder.ForceScan()
}
}
}
}()
return nil
}
// GetFinder returns a register finder
func (h *HardwareManager) GetFinder(finderName string) (PeripheralFinder, error) {
finder, exists := h.finders[finderName]
if !exists {
log.Error().Str("file", "hardware").Str("finderName", finderName).Msg("unable to get the finder")
return nil, fmt.Errorf("unable to locate the '%s' finder", finderName)
}
log.Debug().Str("file", "hardware").Str("finderName", finderName).Msg("got finder")
return finder, nil
}
// RegisterFinder registers a new peripherals finder
func (h *HardwareManager) RegisterFinder(finder PeripheralFinder) {
h.finders[finder.GetName()] = finder
log.Info().Str("file", "hardware").Str("finderName", finder.GetName()).Msg("finder registered")
}
// // GetPeripheral gets the peripheral object from the parent finder
// func (h *HardwareManager) GetPeripheral(finderName string, peripheralID string) (Peripheral, bool) {
// // Get the finder
// parentFinder, found := h.finders[finderName]
// // If no finder found, return false
// if !found {
// log.Error().Str("file", "hardware").Str("finderName", finderName).Msg("unable to get the finder")
// return nil, false
// }
// log.Trace().Str("file", "hardware").Str("finderName", parentFinder.GetName()).Msg("finder got")
// // Contact the finder to get the peripheral
// return parentFinder.GetPeripheral(peripheralID)
// }
// Scan scans all the peripherals for the registered finders
func (h *HardwareManager) Scan() error {
h.peripheralsScanTrigger <- struct{}{}
return nil
}
// 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.finders {
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
}
// emitPeripheralsChanges compares the old and new peripherals to determine which ones have been added or removed.
func emitPeripheralsChanges(ctx context.Context, oldPeripherals map[string]PeripheralInfo, newPeripherals map[string]PeripheralInfo) {
log.Trace().Any("oldList", oldPeripherals).Any("newList", newPeripherals).Msg("emitting peripherals changes to the front")
// Identify removed peripherals: present in the old list but not in the new list
for oldPeriphName := range oldPeripherals {
if _, exists := newPeripherals[oldPeriphName]; !exists {
runtime.EventsEmit(ctx, string(PeripheralRemoval), oldPeripherals[oldPeriphName])
log.Trace().Str("file", "hardware").Str("event", string(PeripheralRemoval)).Msg("emit peripheral removal event")
}
}
// Identify added peripherals: present in the new list but not in the old list
for newPeriphName := range newPeripherals {
if _, exists := oldPeripherals[newPeriphName]; !exists {
runtime.EventsEmit(ctx, string(PeripheralArrival), newPeripherals[newPeriphName])
log.Trace().Str("file", "hardware").Str("event", string(PeripheralArrival)).Msg("emit peripheral arrival event")
}
}
}