fixed: create peripheral

This commit is contained in:
2025-11-30 18:33:00 +01:00
parent d1fda9f075
commit 7f60f7b8d7
8 changed files with 83 additions and 138 deletions

View File

@@ -40,144 +40,102 @@ const (
PeripheralStatusActivated PeripheralStatus = "PERIPHERAL_ACTIVATED"
)
// EventBus handles events between hardware and finders
type EventBus struct {
register map[string][]PeripheralFinder // Register is a map[peripheralType (string)][]Finder
}
// SubscribeType is called from finders that want to subscribe for a peripheral loaded in project
func (b *EventBus) SubscribeType(protocolName string, finder PeripheralFinder) {
// Check if we need to initialize the slice (key not found)
if _, found := b.register[protocolName]; !found {
b.register[protocolName] = make([]PeripheralFinder, 0)
}
// Add the finder to the list of subscription
b.register[protocolName] = append(b.register[protocolName], finder)
}
// EmitSavedPeripheral emits a peripheral loaded event for all the finders suscribed to the peripheral type
func (b *EventBus) EmitSavedPeripheral(ctx context.Context, peripheralInfo PeripheralInfo) (string, error) {
finders, found := b.register[peripheralInfo.ProtocolName]
if !found {
return "", nil
}
for _, finder := range finders {
err := finder.Create(ctx, peripheralInfo)
if err != nil {
log.Err(err).Str("finder", finder.GetName()).Str("S/N", peripheralInfo.SerialNumber).Msg("unable to create the peripheral")
}
}
return "", nil
}
// EmitUnsavedPeripheral emits a peripheral unloaded event for all the finders suscribed to the peripheral type
func (b *EventBus) EmitUnsavedPeripheral(ctx context.Context, peripheral Peripheral) (string, error) {
finders, found := b.register[peripheral.GetInfo().ProtocolName]
if !found {
return "", nil
}
for _, finder := range finders {
err := finder.Remove(ctx, peripheral)
if err != nil {
log.Err(err).Str("finder", finder.GetName()).Str("S/N", peripheral.GetInfo().SerialNumber).Msg("unable to remove the peripheral")
}
}
return "", nil
}
// Manager is the class who manages the hardware
type Manager struct {
mu sync.Mutex
wg sync.WaitGroup
finders map[string]PeripheralFinder // The map of peripherals finders
peripherals map[string]Peripheral // The current list of peripherals
savedPeripherals map[string]PeripheralInfo // The list of stored peripherals
eventBus EventBus // The hardware event bus
finders map[string]PeripheralFinder // The map of peripherals finders
DetectedPeripherals map[string]Peripheral // The current list of peripherals
SavedPeripherals map[string]PeripheralInfo // The list of stored peripherals
}
// NewManager creates a new hardware manager
func NewManager() *Manager {
log.Trace().Str("package", "hardware").Msg("Hardware instance created")
return &Manager{
finders: make(map[string]PeripheralFinder),
peripherals: make(map[string]Peripheral, 0),
savedPeripherals: make(map[string]PeripheralInfo, 0),
eventBus: EventBus{
make(map[string][]PeripheralFinder),
},
finders: make(map[string]PeripheralFinder),
DetectedPeripherals: make(map[string]Peripheral, 0),
SavedPeripherals: make(map[string]PeripheralInfo, 0),
}
}
// CreatePeripheral asks the providers to create a new peripheral
func (h *Manager) CreatePeripheral(ctx context.Context, peripheralInfo PeripheralInfo) {
// Emit an event to the hardware event bus
h.eventBus.EmitSavedPeripheral(ctx, peripheralInfo)
}
// RegisterPeripheral registers a new peripheral
func (h *Manager) RegisterPeripheral(ctx context.Context, peripheralData PeripheralInfo) (string, error) {
func (h *Manager) RegisterPeripheral(ctx context.Context, peripheralInfo PeripheralInfo) (string, error) {
h.mu.Lock()
defer h.mu.Unlock()
// Do not save if the peripheral doesn't have a S/N
if peripheralData.SerialNumber == "" {
return "", nil
// Create the peripheral from its finder (if needed)
if finder, found := h.finders[peripheralInfo.ProtocolName]; found {
var err error
peripheralInfo, err = finder.Create(ctx, peripheralInfo)
if err != nil {
return "", err
}
}
h.savedPeripherals[peripheralData.SerialNumber] = peripheralData
// Do not save if the peripheral doesn't have a S/N
if peripheralInfo.SerialNumber == "" {
return "", fmt.Errorf("serial number is empty for this peripheral")
}
runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralData, PeripheralStatusDisconnected)
h.SavedPeripherals[peripheralInfo.SerialNumber] = peripheralInfo
runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralInfo, PeripheralStatusDisconnected)
// If already detected, connect it
if peripheral, ok := h.peripherals[peripheralData.SerialNumber]; ok {
if peripheral, ok := h.DetectedPeripherals[peripheralInfo.SerialNumber]; ok {
h.wg.Add(1)
go func() {
defer h.wg.Done()
err := peripheral.Connect(ctx)
if err != nil {
log.Err(err).Str("file", "FTDIFinder").Str("peripheralSN", peripheralData.SerialNumber).Msg("unable to connect the peripheral")
log.Err(err).Str("file", "FTDIFinder").Str("peripheralSN", peripheralInfo.SerialNumber).Msg("unable to connect the peripheral")
return
}
// Peripheral connected, activate it
err = peripheral.Activate(ctx)
if err != nil {
log.Err(err).Str("file", "FTDIFinder").Str("peripheralSN", peripheralData.SerialNumber).Msg("unable to activate the FTDI peripheral")
log.Err(err).Str("file", "FTDIFinder").Str("peripheralSN", peripheralInfo.SerialNumber).Msg("unable to activate the FTDI peripheral")
return
}
}()
}
// Emits the event in the hardware
runtime.EventsEmit(ctx, string(PeripheralLoad), peripheralData)
runtime.EventsEmit(ctx, string(PeripheralLoad), peripheralInfo)
return peripheralData.SerialNumber, nil
return peripheralInfo.SerialNumber, nil
}
// UnregisterPeripheral unregisters an existing peripheral
func (h *Manager) UnregisterPeripheral(ctx context.Context, peripheralData PeripheralInfo) error {
func (h *Manager) UnregisterPeripheral(ctx context.Context, peripheralInfo PeripheralInfo) error {
h.mu.Lock()
defer h.mu.Unlock()
if peripheral, detected := h.peripherals[peripheralData.SerialNumber]; detected {
if peripheral, detected := h.DetectedPeripherals[peripheralInfo.SerialNumber]; detected {
// Deactivating peripheral
err := peripheral.Deactivate(ctx)
if err != nil {
log.Err(err).Str("sn", peripheralData.SerialNumber).Msg("unable to deactivate the peripheral")
log.Err(err).Str("sn", peripheralInfo.SerialNumber).Msg("unable to deactivate the peripheral")
return nil
}
// Disconnecting peripheral
err = peripheral.Disconnect(ctx)
if err != nil {
log.Err(err).Str("sn", peripheralData.SerialNumber).Msg("unable to disconnect the peripheral")
log.Err(err).Str("sn", peripheralInfo.SerialNumber).Msg("unable to disconnect the peripheral")
return nil
}
// Emit the unload event
h.eventBus.EmitUnsavedPeripheral(ctx, peripheral)
// Remove the peripheral from its finder (if needed)
if finder, found := h.finders[peripheralInfo.ProtocolName]; found {
err = finder.Remove(ctx, peripheral)
if err != nil {
return err
}
}
}
delete(h.savedPeripherals, peripheralData.SerialNumber)
runtime.EventsEmit(ctx, string(PeripheralUnload), peripheralData)
delete(h.SavedPeripherals, peripheralInfo.SerialNumber)
runtime.EventsEmit(ctx, string(PeripheralUnload), peripheralInfo)
return nil
}
@@ -185,10 +143,10 @@ func (h *Manager) UnregisterPeripheral(ctx context.Context, peripheralData Perip
// GetPeripheralSettings gets the peripheral settings
func (h *Manager) GetPeripheralSettings(peripheralSN string) (map[string]any, error) {
// Return the specified peripheral
peripheral, found := h.peripherals[peripheralSN]
peripheral, found := h.DetectedPeripherals[peripheralSN]
if !found {
// Peripheral not detected, return the last settings saved
if savedPeripheral, isFound := h.savedPeripherals[peripheralSN]; isFound {
if savedPeripheral, isFound := h.SavedPeripherals[peripheralSN]; isFound {
return savedPeripheral.Settings, nil
}
return nil, fmt.Errorf("unable to found the peripheral")
@@ -198,7 +156,7 @@ func (h *Manager) GetPeripheralSettings(peripheralSN string) (map[string]any, er
// SetPeripheralSettings sets the peripheral settings
func (h *Manager) SetPeripheralSettings(ctx context.Context, peripheralSN string, settings map[string]any) error {
peripheral, found := h.peripherals[peripheralSN]
peripheral, found := h.DetectedPeripherals[peripheralSN]
if !found {
return fmt.Errorf("unable to found the FTDI peripheral")
}
@@ -210,7 +168,7 @@ func (h *Manager) Start(ctx context.Context) error {
// Register all the finders to use as hardware scanners
h.RegisterFinder(NewFTDIFinder(3 * time.Second))
h.RegisterFinder(NewOS2LFinder(h.eventBus))
h.RegisterFinder(NewOS2LFinder())
h.RegisterFinder(NewMIDIFinder(3 * time.Second))
for finderName, finder := range h.finders {
@@ -237,17 +195,12 @@ func (h *Manager) Start(ctx context.Context) error {
}
// OnPeripheralArrival is called when a peripheral arrives in the system
func (h *Manager) OnPeripheralArrival(ctx context.Context, peripheral Peripheral, needSave bool) {
// Save the peripheral in the project if needed
if needSave {
h.RegisterPeripheral(ctx, peripheral.GetInfo())
}
func (h *Manager) OnPeripheralArrival(ctx context.Context, peripheral Peripheral) {
// Add the peripheral to the detected hardware
h.peripherals[peripheral.GetInfo().SerialNumber] = peripheral
h.DetectedPeripherals[peripheral.GetInfo().SerialNumber] = peripheral
// If the peripheral is saved in the project, connect it
if _, saved := h.savedPeripherals[peripheral.GetInfo().SerialNumber]; saved {
if _, saved := h.SavedPeripherals[peripheral.GetInfo().SerialNumber]; saved {
h.wg.Add(1)
go func(p Peripheral) {
defer h.wg.Done()
@@ -286,7 +239,7 @@ func (h *Manager) OnPeripheralRemoval(ctx context.Context, peripheral Peripheral
}(peripheral)
// Remove the peripheral from the hardware
delete(h.peripherals, peripheral.GetInfo().SerialNumber)
delete(h.DetectedPeripherals, peripheral.GetInfo().SerialNumber)
// TODO: Update the Peripheral reference in the corresponding devices
runtime.EventsEmit(ctx, string(PeripheralRemoval), peripheral.GetInfo())
@@ -323,7 +276,7 @@ func (h *Manager) WaitStop() error {
// Wait for all the peripherals to close
log.Trace().Str("file", "MIDIFinder").Msg("closing all MIDI peripherals")
for registeredPeripheralSN, registeredPeripheral := range h.peripherals {
for registeredPeripheralSN, registeredPeripheral := range h.DetectedPeripherals {
err := registeredPeripheral.WaitStop()
if err != nil {
errs = append(errs, fmt.Errorf("%s: %w", registeredPeripheralSN, err))