From 848d2758d7de8552615d0b007327356088d50cd9 Mon Sep 17 00:00:00 2001 From: Valentin Boulanger Date: Sat, 29 Nov 2025 17:42:42 +0100 Subject: [PATCH] Adapting interfaces --- .../Settings/InputsOutputsContent.svelte | 16 +- hardware/FTDIFinder.go | 174 ++------------- hardware/FTDIPeripheral.go | 2 +- hardware/MIDIFinder.go | 167 ++------------- hardware/MIDIPeripheral.go | 4 +- hardware/OS2LFinder.go | 131 ++---------- hardware/OS2LPeripheral.go | 2 +- hardware/hardware.go | 202 ++++++++++++++---- hardware/interfaces.go | 32 ++- peripherals.go | 86 ++------ project.go | 12 +- 11 files changed, 264 insertions(+), 564 deletions(-) diff --git a/frontend/src/components/Settings/InputsOutputsContent.svelte b/frontend/src/components/Settings/InputsOutputsContent.svelte index f67b102..591be60 100644 --- a/frontend/src/components/Settings/InputsOutputsContent.svelte +++ b/frontend/src/components/Settings/InputsOutputsContent.svelte @@ -4,9 +4,19 @@ import { t, _ } from 'svelte-i18n' import { generateToast, needProjectSave, peripherals, colors } from "../../stores"; import { get } from "svelte/store" - import { UpdatePeripheralSettings, GetPeripheralSettings, RemovePeripheral, AddPeripheral } from "../../../wailsjs/go/main/App"; + import { UpdatePeripheralSettings, GetPeripheralSettings, RemovePeripheral, AddPeripheral, CreatePeripheral } from "../../../wailsjs/go/main/App"; import RoundedButton from "../General/RoundedButton.svelte"; + // Create a new peripheral + function createPeripheral(peripheral){ + // Add the peripheral to the project (backend) + CreatePeripheral(peripheral) + .catch((error) => { + console.log("Unable to create the peripheral: " + error) + generateToast('danger', 'bx-error', $_("addPeripheralErrorToast")) + }) + } + // Add the peripheral to the project function addPeripheral(peripheral){ // Add the peripheral to the project (backend) @@ -94,8 +104,8 @@

{$_("projectHardwareOthersLabel")}

- addPeripheral({Name: "OS2L virtual device", ProtocolName: "OS2L", SerialNumber: ""})} - on:dblclick={() => addPeripheral({Name: "OS2L virtual device", ProtocolName: "OS2L", SerialNumber: ""})} + createPeripheral({Name: "OS2L virtual device", ProtocolName: "OS2L", SerialNumber: ""})} + on:dblclick={() => createPeripheral({Name: "OS2L virtual device", ProtocolName: "OS2L", SerialNumber: ""})} status="PERIPHERAL_CONNECTED" title={"OS2L virtual device"} type={"OS2L"} location={""} addable={true}/> diff --git a/hardware/FTDIFinder.go b/hardware/FTDIFinder.go index c2b8e25..d0ce37a 100644 --- a/hardware/FTDIFinder.go +++ b/hardware/FTDIFinder.go @@ -2,7 +2,6 @@ package hardware import ( "context" - "errors" "fmt" goRuntime "runtime" "sync" @@ -10,7 +9,6 @@ import ( "unsafe" "github.com/rs/zerolog/log" - "github.com/wailsapp/wails/v2/pkg/runtime" ) /* @@ -25,13 +23,12 @@ type FTDIFinder struct { wg sync.WaitGroup mu sync.Mutex - saved map[string]PeripheralInfo // Peripherals saved in the project detected map[string]*FTDIPeripheral // Detected peripherals scanEvery time.Duration // Scans peripherals periodically - onArrival func(p PeripheralInfo) // When a peripheral arrives - onRemoval func(p PeripheralInfo) // When a peripheral goes away + onArrival func(context.Context, Peripheral) // When a peripheral arrives + onRemoval func(context.Context, Peripheral) // When a peripheral goes away } // NewFTDIFinder creates a new FTDI finder @@ -39,79 +36,20 @@ func NewFTDIFinder(scanEvery time.Duration) *FTDIFinder { log.Trace().Str("file", "FTDIFinder").Msg("FTDI finder created") return &FTDIFinder{ scanEvery: scanEvery, - saved: make(map[string]PeripheralInfo), detected: make(map[string]*FTDIPeripheral), } } // OnArrival is the callback function when a new peripheral arrives -func (f *FTDIFinder) OnArrival(cb func(p PeripheralInfo)) { +func (f *FTDIFinder) OnArrival(cb func(context.Context, Peripheral)) { f.onArrival = cb } // OnRemoval i the callback when a peripheral goes away -func (f *FTDIFinder) OnRemoval(cb func(p PeripheralInfo)) { +func (f *FTDIFinder) OnRemoval(cb func(context.Context, Peripheral)) { f.onRemoval = cb } -// RegisterPeripheral registers a new peripheral -func (f *FTDIFinder) RegisterPeripheral(ctx context.Context, peripheralData PeripheralInfo) (string, error) { - f.mu.Lock() - defer f.mu.Unlock() - - f.saved[peripheralData.SerialNumber] = peripheralData - runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralData, PeripheralStatusDisconnected) - - // If already detected, connect it - if peripheral, ok := f.detected[peripheralData.SerialNumber]; ok { - f.wg.Add(1) - go func() { - defer f.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") - 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") - return - } - }() - } - - // Emits the event in the hardware - runtime.EventsEmit(ctx, "LOAD_PERIPHERAL", peripheralData) - - return peripheralData.SerialNumber, nil -} - -// UnregisterPeripheral unregisters an existing peripheral -func (f *FTDIFinder) UnregisterPeripheral(ctx context.Context, peripheralData PeripheralInfo) error { - f.mu.Lock() - defer f.mu.Unlock() - - if peripheral, detected := f.detected[peripheralData.SerialNumber]; detected { - // Deactivating peripheral - err := peripheral.Deactivate(ctx) - if err != nil { - log.Err(err).Str("sn", peripheralData.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") - return nil - } - } - delete(f.saved, peripheralData.SerialNumber) - runtime.EventsEmit(ctx, "UNLOAD_PERIPHERAL", peripheralData) - - return nil -} - // Initialize initializes the FTDI finder func (f *FTDIFinder) Initialize() error { // Check platform @@ -123,6 +61,16 @@ func (f *FTDIFinder) Initialize() error { return nil } +// Create creates a new peripheral, based on the peripheral information (manually created) +func (f *FTDIFinder) Create(ctx context.Context, peripheralInfo PeripheralInfo) (string, error) { + return "", nil +} + +// Remove removes an existing peripheral (manually created) +func (f *FTDIFinder) Remove(ctx context.Context, peripheral Peripheral) error { + return nil +} + // Start starts the finder and search for peripherals func (f *FTDIFinder) Start(ctx context.Context) error { f.wg.Add(1) @@ -147,45 +95,11 @@ func (f *FTDIFinder) Start(ctx context.Context) error { return nil } -// ForceScan explicitly asks for scanning peripherals -func (f *FTDIFinder) ForceScan() { - // select { - // case f.scanChannel <- struct{}{}: - // default: - // // Ignore if the channel is full or if it is closed - // } -} - // GetName returns the name of the driver func (f *FTDIFinder) GetName() string { return "FTDI" } -// GetPeripheralSettings gets the peripheral settings -func (f *FTDIFinder) GetPeripheralSettings(peripheralID string) (map[string]interface{}, error) { - // Return the specified peripheral - peripheral, found := f.detected[peripheralID] - if !found { - // FTDI not detected, return the last settings saved - if savedPeripheral, isFound := f.saved[peripheralID]; isFound { - return savedPeripheral.Settings, nil - } - return nil, fmt.Errorf("unable to found the peripheral") - } - return peripheral.GetSettings(), nil -} - -// SetPeripheralSettings sets the peripheral settings -func (f *FTDIFinder) SetPeripheralSettings(ctx context.Context, peripheralID string, settings map[string]any) error { - // Return the specified peripheral - peripheral, found := f.detected[peripheralID] - if !found { - return fmt.Errorf("unable to found the FTDI peripheral") - } - log.Debug().Str("file", "FTDIFinder").Str("peripheralID", peripheralID).Msg("peripheral found by the FTDI finder") - return peripheral.SetSettings(settings) -} - // scanPeripherals scans the FTDI peripherals func (f *FTDIFinder) scanPeripherals(ctx context.Context) error { log.Trace().Str("file", "FTDIFinder").Msg("FTDI scan triggered") @@ -227,56 +141,27 @@ func (f *FTDIFinder) scanPeripherals(ctx context.Context) error { // Detect arrivals for sn, peripheralData := range currentMap { + // If the scanned peripheral isn't in the detected list, create it if _, known := f.detected[sn]; !known { + peripheral := NewFTDIPeripheral(peripheralData) - f.detected[sn] = peripheral if f.onArrival != nil { - f.onArrival(peripheralData) - } - log.Info().Str("sn", sn).Str("name", peripheralData.Name).Msg("[FTDI] New peripheral detected") - - // If the peripheral is saved in the project => connect - if _, saved := f.saved[sn]; saved { - f.wg.Add(1) - go func(p PeripheralInfo) { - defer f.wg.Done() - err := peripheral.Connect(ctx) - if err != nil { - log.Err(err).Str("sn", p.SerialNumber).Msg("unable to connect the FTDI peripheral") - return - } - err = peripheral.Activate(ctx) - if err != nil { - log.Err(err).Str("sn", p.SerialNumber).Msg("unable to activate the FTDI peripheral") - return - } - }(peripheralData) + f.onArrival(ctx, peripheral) } } } // Detect removals - for sn, oldPeripheral := range f.detected { - if _, still := currentMap[sn]; !still { - - // Properly clean the DMX device - err := oldPeripheral.Deactivate(ctx) - if err != nil { - log.Err(err).Str("sn", sn).Msg("unable to deactivate the FTDI peripheral after disconnection") - } - err = oldPeripheral.Disconnect(ctx) - if err != nil { - log.Err(err).Str("sn", sn).Msg("unable to disconnect the FTDI peripheral after disconnection") - } + for detectedSN, detectedPeripheral := range f.detected { + if _, still := currentMap[detectedSN]; !still { // Delete it from the detected list - delete(f.detected, sn) - log.Info().Str("sn", sn).Str("name", oldPeripheral.GetInfo().Name).Msg("[FTDI] peripheral removed") + delete(f.detected, detectedSN) // Execute the removal callback if f.onRemoval != nil { - f.onRemoval(oldPeripheral.GetInfo()) + f.onRemoval(ctx, detectedPeripheral) } } } @@ -287,26 +172,9 @@ func (f *FTDIFinder) scanPeripherals(ctx context.Context) error { func (f *FTDIFinder) WaitStop() error { log.Trace().Str("file", "FTDIFinder").Msg("stopping the FTDI finder...") - // Close the channel - // close(f.scanChannel) - - // Wait for all the peripherals to close - log.Trace().Str("file", "FTDIFinder").Msg("closing all FTDI peripherals") - var errs []error - for registeredPeripheralSN, registeredPeripheral := range f.detected { - err := registeredPeripheral.WaitStop() - if err != nil { - errs = append(errs, fmt.Errorf("%s: %w", registeredPeripheralSN, err)) - } - } - // Wait for goroutines to stop f.wg.Wait() - // Returning errors - if len(errs) > 0 { - return errors.Join(errs...) - } log.Trace().Str("file", "FTDIFinder").Msg("FTDI finder stopped") return nil } diff --git a/hardware/FTDIPeripheral.go b/hardware/FTDIPeripheral.go index ac9a088..b205698 100644 --- a/hardware/FTDIPeripheral.go +++ b/hardware/FTDIPeripheral.go @@ -129,7 +129,7 @@ func (p *FTDIPeripheral) Deactivate(ctx context.Context) error { } // SetSettings sets a specific setting for this peripheral -func (p *FTDIPeripheral) SetSettings(settings map[string]interface{}) error { +func (p *FTDIPeripheral) SetSettings(ctx context.Context, settings map[string]any) error { return errors.Errorf("unable to set the settings: not implemented") } diff --git a/hardware/MIDIFinder.go b/hardware/MIDIFinder.go index d062ef2..ec3929b 100644 --- a/hardware/MIDIFinder.go +++ b/hardware/MIDIFinder.go @@ -2,7 +2,6 @@ package hardware import ( "context" - "errors" "fmt" "regexp" "strconv" @@ -11,7 +10,6 @@ import ( "time" "github.com/rs/zerolog/log" - "github.com/wailsapp/wails/v2/pkg/runtime" "gitlab.com/gomidi/rtmididrv" ) @@ -20,13 +18,12 @@ type MIDIFinder struct { wg sync.WaitGroup mu sync.Mutex - saved map[string]PeripheralInfo // Peripherals saved in the project detected map[string]*MIDIPeripheral // Detected peripherals scanEvery time.Duration // Scans peripherals periodically - onArrival func(p PeripheralInfo) // When a peripheral arrives - onRemoval func(p PeripheralInfo) // When a peripheral goes away + onArrival func(context.Context, Peripheral) // When a peripheral arrives + onRemoval func(context.Context, Peripheral) // When a peripheral goes away } // NewMIDIFinder creates a new MIDI finder @@ -34,18 +31,17 @@ func NewMIDIFinder(scanEvery time.Duration) *MIDIFinder { log.Trace().Str("file", "MIDIFinder").Msg("MIDI finder created") return &MIDIFinder{ scanEvery: scanEvery, - saved: make(map[string]PeripheralInfo), detected: make(map[string]*MIDIPeripheral), } } // OnArrival is the callback function when a new peripheral arrives -func (f *MIDIFinder) OnArrival(cb func(p PeripheralInfo)) { +func (f *MIDIFinder) OnArrival(cb func(context.Context, Peripheral)) { f.onArrival = cb } // OnRemoval i the callback when a peripheral goes away -func (f *MIDIFinder) OnRemoval(cb func(p PeripheralInfo)) { +func (f *MIDIFinder) OnRemoval(cb func(context.Context, Peripheral)) { f.onRemoval = cb } @@ -55,59 +51,13 @@ func (f *MIDIFinder) Initialize() error { return nil } -// RegisterPeripheral registers a new peripheral -func (f *MIDIFinder) RegisterPeripheral(ctx context.Context, peripheralData PeripheralInfo) (string, error) { - f.mu.Lock() - defer f.mu.Unlock() - - f.saved[peripheralData.SerialNumber] = peripheralData - runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralData, PeripheralStatusDisconnected) - - // If already detected, connect it - if peripheral, ok := f.detected[peripheralData.SerialNumber]; ok { - f.wg.Add(1) - go func() { - defer f.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") - 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") - return - } - }() - } - - // Emits the event in the hardware - runtime.EventsEmit(ctx, "LOAD_PERIPHERAL", peripheralData) - return peripheralData.SerialNumber, nil +// Create creates a new peripheral, based on the peripheral information (manually created) +func (f *MIDIFinder) Create(ctx context.Context, peripheralInfo PeripheralInfo) (string, error) { + return "", nil } -// UnregisterPeripheral unregisters an existing peripheral -func (f *MIDIFinder) UnregisterPeripheral(ctx context.Context, peripheralData PeripheralInfo) error { - f.mu.Lock() - defer f.mu.Unlock() - - if peripheral, detected := f.detected[peripheralData.SerialNumber]; detected { - // Deactivating peripheral - err := peripheral.Deactivate(ctx) - if err != nil { - log.Err(err).Str("sn", peripheralData.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") - return nil - } - } - delete(f.saved, peripheralData.SerialNumber) - runtime.EventsEmit(ctx, "UNLOAD_PERIPHERAL", peripheralData) +// Remove removes an existing peripheral (manually created) +func (f *MIDIFinder) Remove(ctx context.Context, peripheral Peripheral) error { return nil } @@ -139,26 +89,9 @@ func (f *MIDIFinder) Start(ctx context.Context) error { func (f *MIDIFinder) WaitStop() error { log.Trace().Str("file", "MIDIFinder").Msg("stopping the MIDI finder...") - // Close the channel - // close(f.scanChannel) - - // Wait for all the peripherals to close - log.Trace().Str("file", "MIDIFinder").Msg("closing all MIDI peripherals") - var errs []error - for registeredPeripheralSN, registeredPeripheral := range f.detected { - err := registeredPeripheral.WaitStop() - if err != nil { - errs = append(errs, fmt.Errorf("%s: %w", registeredPeripheralSN, err)) - } - } - // Wait for goroutines to stop f.wg.Wait() - // Returning errors - if len(errs) > 0 { - return errors.Join(errs...) - } log.Trace().Str("file", "MIDIFinder").Msg("MIDI finder stopped") return nil } @@ -168,31 +101,6 @@ func (f *MIDIFinder) GetName() string { return "MIDI" } -// GetPeripheralSettings gets the peripheral settings -func (f *MIDIFinder) GetPeripheralSettings(peripheralID string) (map[string]interface{}, error) { - // Return the specified peripheral - peripheral, found := f.detected[peripheralID] - if !found { - // FTDI not detected, return the last settings saved - if savedPeripheral, isFound := f.saved[peripheralID]; isFound { - return savedPeripheral.Settings, nil - } - return nil, fmt.Errorf("unable to found the peripheral") - } - return peripheral.GetSettings(), nil -} - -// SetPeripheralSettings sets the peripheral settings -func (f *MIDIFinder) SetPeripheralSettings(ctx context.Context, peripheralID string, settings map[string]interface{}) error { - // Return the specified peripheral - peripheral, found := f.detected[peripheralID] - if !found { - return fmt.Errorf("unable to found the MIDI peripheral") - } - log.Debug().Str("file", "MIDIFinder").Str("peripheralID", peripheralID).Msg("peripheral found by the MIDI finder") - return peripheral.SetSettings(settings) -} - func splitStringAndNumber(input string) (string, int, error) { // Regular expression to match the text part and the number at the end re := regexp.MustCompile(`^(.*?)(\d+)$`) @@ -214,11 +122,6 @@ func splitStringAndNumber(input string) (string, int, error) { return "", 0, fmt.Errorf("no number found at the end of the string") } -// ForceScan explicily asks for scanning peripherals -func (f *MIDIFinder) ForceScan() { - // f.scanChannel <- struct{}{} -} - // scanPeripherals scans the MIDI peripherals func (f *MIDIFinder) scanPeripherals(ctx context.Context) error { currentMap := make(map[string]*MIDIPeripheral) @@ -298,26 +201,7 @@ func (f *MIDIFinder) scanPeripherals(ctx context.Context) error { f.detected[sn] = peripheral if f.onArrival != nil { - f.onArrival(discovery.GetInfo()) - } - log.Info().Str("sn", sn).Str("name", discovery.GetInfo().SerialNumber).Msg("[MIDI] New peripheral detected") - - // If the peripheral is saved in the project => connect - if _, saved := f.saved[sn]; saved { - f.wg.Add(1) - go func(p PeripheralInfo) { - defer f.wg.Done() - err := peripheral.Connect(ctx) - if err != nil { - log.Err(err).Str("sn", p.SerialNumber).Msg("unable to connect the MIDI peripheral") - return - } - err = peripheral.Activate(ctx) - if err != nil { - log.Err(err).Str("sn", p.SerialNumber).Msg("unable to activate the MIDI peripheral") - return - } - }(discovery.GetInfo()) + f.onArrival(ctx, discovery) } } } @@ -326,24 +210,15 @@ func (f *MIDIFinder) scanPeripherals(ctx context.Context) error { for sn, oldPeripheral := range f.detected { if _, still := currentMap[sn]; !still { - // Properly clean the DMX device - err := oldPeripheral.Deactivate(ctx) - if err != nil { - log.Err(err).Str("sn", sn).Msg("unable to deactivate the MIDI peripheral after disconnection") - } - err = oldPeripheral.Disconnect(ctx) - if err != nil { - log.Err(err).Str("sn", sn).Msg("unable to disconnect the MIDI peripheral after disconnection") - } - - // Delete it from the detected list - delete(f.detected, sn) log.Info().Str("sn", sn).Str("name", oldPeripheral.GetInfo().Name).Msg("[MIDI] peripheral removed") // Execute the removal callback if f.onRemoval != nil { - f.onRemoval(oldPeripheral.GetInfo()) + f.onRemoval(ctx, oldPeripheral) } + + // Delete it from the detected list + delete(f.detected, sn) } } return nil @@ -370,17 +245,3 @@ func normalizeName(raw string) string { return strings.Join(parts, " ") } - -// func normalizeName(name string) string { -// // Cas communs : "MIDIIN2 (XXX)" → "XXX" -// if strings.Contains(name, "(") && strings.Contains(name, ")") { -// start := strings.Index(name, "(") -// end := strings.Index(name, ")") -// if start < end { -// return strings.TrimSpace(name[start+1 : end]) -// } -// } - -// // Sinon, on retourne tel quel -// return strings.TrimSpace(name) -// } diff --git a/hardware/MIDIPeripheral.go b/hardware/MIDIPeripheral.go index 09d8243..2a5b248 100644 --- a/hardware/MIDIPeripheral.go +++ b/hardware/MIDIPeripheral.go @@ -100,13 +100,13 @@ func (p *MIDIPeripheral) Deactivate(ctx context.Context) error { } // SetSettings sets a specific setting for this peripheral -func (p *MIDIPeripheral) SetSettings(settings map[string]interface{}) error { +func (p *MIDIPeripheral) SetSettings(ctx context.Context, settings map[string]any) error { p.settings = settings return nil } // SetDeviceProperty - not implemented for this kind of peripheral -func (p *MIDIPeripheral) SetDeviceProperty(context.Context, uint32, uint32, byte) error { +func (p *MIDIPeripheral) SetDeviceProperty(context.Context, uint32, byte) error { return nil } diff --git a/hardware/OS2LFinder.go b/hardware/OS2LFinder.go index d4c0684..a1ae9f9 100644 --- a/hardware/OS2LFinder.go +++ b/hardware/OS2LFinder.go @@ -2,7 +2,6 @@ package hardware import ( "context" - "errors" "fmt" "math/rand" "strings" @@ -17,17 +16,17 @@ type OS2LFinder struct { wg sync.WaitGroup mu sync.Mutex - saved map[string]*OS2LPeripheral // The list of saved peripherals + detected map[string]*OS2LPeripheral // The list of saved peripherals - onArrival func(p PeripheralInfo) // When a peripheral arrives - onRemoval func(p PeripheralInfo) // When a peripheral goes away + onArrival func(context.Context, Peripheral) // When a peripheral arrives + onRemoval func(context.Context, Peripheral) // When a peripheral goes away } // NewOS2LFinder creates a new OS2L finder func NewOS2LFinder() *OS2LFinder { log.Trace().Str("file", "OS2LFinder").Msg("OS2L finder created") return &OS2LFinder{ - saved: make(map[string]*OS2LPeripheral), + detected: make(map[string]*OS2LPeripheral), } } @@ -38,91 +37,47 @@ func (f *OS2LFinder) Initialize() error { } // OnArrival is the callback function when a new peripheral arrives -func (f *OS2LFinder) OnArrival(cb func(p PeripheralInfo)) { +func (f *OS2LFinder) OnArrival(cb func(context.Context, Peripheral)) { f.onArrival = cb } // OnRemoval i the callback when a peripheral goes away -func (f *OS2LFinder) OnRemoval(cb func(p PeripheralInfo)) { +func (f *OS2LFinder) OnRemoval(cb func(context.Context, Peripheral)) { f.onRemoval = cb } -// RegisterPeripheral registers a new peripheral -func (f *OS2LFinder) RegisterPeripheral(ctx context.Context, peripheralData PeripheralInfo) (string, error) { - f.mu.Lock() - defer f.mu.Unlock() - +// Create creates a new peripheral, based on the peripheral information (manually created) +func (f *OS2LFinder) Create(ctx context.Context, peripheralInfo PeripheralInfo) (string, error) { // If the SerialNumber is empty, generate another one - if peripheralData.SerialNumber == "" { - peripheralData.SerialNumber = strings.ToUpper(fmt.Sprintf("%08x", rand.Intn(1<<32))) + if peripheralInfo.SerialNumber == "" { + peripheralInfo.SerialNumber = strings.ToUpper(fmt.Sprintf("%08x", rand.Intn(1<<32))) } // Create a new OS2L peripheral - peripheral, err := NewOS2LPeripheral(peripheralData) + peripheral, err := NewOS2LPeripheral(peripheralInfo) if err != nil { return "", fmt.Errorf("unable to create the OS2L peripheral: %w", err) } + // Set the event callback peripheral.SetEventCallback(func(event any) { - runtime.EventsEmit(ctx, string(PeripheralEventEmitted), peripheralData.SerialNumber, event) + runtime.EventsEmit(ctx, string(PeripheralEventEmitted), peripheralInfo.SerialNumber, event) }) - f.saved[peripheralData.SerialNumber] = peripheral - log.Trace().Str("file", "OS2LFinder").Str("serialNumber", peripheralData.SerialNumber).Msg("OS2L peripheral created") + f.detected[peripheralInfo.SerialNumber] = peripheral - // New OS2L peripheral has arrived if f.onArrival != nil { - f.onArrival(peripheral.GetInfo()) + f.onArrival(ctx, peripheral) } - - f.wg.Add(1) - go func() { - defer f.wg.Done() - // Connect the OS2L peripheral - err = peripheral.Connect(ctx) - if err != nil { - log.Err(err).Str("file", "OS2LFinder").Str("peripheralSN", peripheralData.SerialNumber).Msg("unable to connect the peripheral") - return - } - // Peripheral connected, activate it - err = peripheral.Activate(ctx) - if err != nil { - log.Err(err).Str("file", "OS2LFinder").Str("peripheralSN", peripheralData.SerialNumber).Msg("unable to activate the OS2L peripheral") - return - } - }() - - // Emits the event in the hardware - runtime.EventsEmit(ctx, "LOAD_PERIPHERAL", peripheralData) - - return peripheralData.SerialNumber, nil + return peripheralInfo.SerialNumber, err } -// UnregisterPeripheral unregisters an existing peripheral -func (f *OS2LFinder) UnregisterPeripheral(ctx context.Context, peripheralData PeripheralInfo) error { - f.mu.Lock() - defer f.mu.Unlock() - - if peripheral, detected := f.saved[peripheralData.SerialNumber]; detected { - // Deactivating peripheral - err := peripheral.Deactivate(ctx) - if err != nil { - log.Err(err).Str("sn", peripheralData.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") - return nil - } +// Remove removes an existing peripheral (manually created) +func (f *OS2LFinder) Remove(ctx context.Context, peripheral Peripheral) error { + if f.onRemoval != nil { + f.onRemoval(ctx, peripheral) } - - // The OS2L peripheral has gone - f.onRemoval(peripheralData) - - delete(f.saved, peripheralData.SerialNumber) - runtime.EventsEmit(ctx, "UNLOAD_PERIPHERAL", peripheralData) + delete(f.detected, peripheral.GetInfo().SerialNumber) return nil } @@ -131,29 +86,6 @@ func (f *OS2LFinder) GetName() string { return "OS2L" } -// GetPeripheralSettings gets the peripheral settings -func (f *OS2LFinder) GetPeripheralSettings(peripheralID string) (map[string]any, error) { - // Return the specified peripheral - peripheral, found := f.saved[peripheralID] - if !found { - log.Error().Str("file", "OS2LFinder").Str("peripheralID", peripheralID).Msg("unable to get this peripheral from the OS2L finder") - return nil, fmt.Errorf("unable to found the peripheral") - } - return peripheral.GetSettings(), nil -} - -// SetPeripheralSettings sets the peripheral settings -func (f *OS2LFinder) SetPeripheralSettings(ctx context.Context, peripheralID string, settings map[string]any) error { - // Return the specified peripheral - peripheral, found := f.saved[peripheralID] - if !found { - return fmt.Errorf("unable to found the FTDI peripheral") - } - - // Set the peripheral settings - return peripheral.SetSettings(ctx, settings) -} - // Start starts the finder func (f *OS2LFinder) Start(ctx context.Context) error { // No peripherals to scan here @@ -164,30 +96,9 @@ func (f *OS2LFinder) Start(ctx context.Context) error { func (f *OS2LFinder) WaitStop() error { log.Trace().Str("file", "OS2LFinder").Msg("stopping the OS2L finder...") - // Close the channel - // close(f.scanChannel) - - // Wait for all the peripherals to close - log.Trace().Str("file", "OS2LFinder").Msg("closing all OS2L peripherals") - var errs []error - for registeredPeripheralSN, registeredPeripheral := range f.saved { - err := registeredPeripheral.WaitStop() - if err != nil { - errs = append(errs, fmt.Errorf("%s: %w", registeredPeripheralSN, err)) - } - } - // Waiting internal tasks f.wg.Wait() - // Returning errors - if len(errs) > 0 { - return errors.Join(errs...) - } log.Trace().Str("file", "OS2LFinder").Msg("OS2L finder stopped") return nil } - -// ForceScan scans the interfaces (not implemented) -func (f *OS2LFinder) ForceScan() { -} diff --git a/hardware/OS2LPeripheral.go b/hardware/OS2LPeripheral.go index ee17343..887e0dc 100644 --- a/hardware/OS2LPeripheral.go +++ b/hardware/OS2LPeripheral.go @@ -260,7 +260,7 @@ func (p *OS2LPeripheral) SetSettings(ctx context.Context, settings map[string]an } // SetDeviceProperty - not implemented for this kind of peripheral -func (p *OS2LPeripheral) SetDeviceProperty(context.Context, uint32, uint32, byte) error { +func (p *OS2LPeripheral) SetDeviceProperty(context.Context, uint32, byte) error { return nil } diff --git a/hardware/hardware.go b/hardware/hardware.go index d581306..e7ded7f 100644 --- a/hardware/hardware.go +++ b/hardware/hardware.go @@ -38,68 +38,188 @@ const ( // 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 []*Peripheral // The current list of peripherals - peripheralsScanTrigger chan struct{} // Trigger the peripherals scans + 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 } // 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([]*Peripheral, 0), - peripheralsScanTrigger: make(chan struct{}), + finders: make(map[string]PeripheralFinder), + peripherals: make(map[string]Peripheral, 0), + savedPeripherals: make(map[string]PeripheralInfo, 0), } } +// RegisterPeripheral registers a new peripheral +func (h *Manager) RegisterPeripheral(ctx context.Context, peripheralData PeripheralInfo) (string, error) { + h.mu.Lock() + defer h.mu.Unlock() + + h.savedPeripherals[peripheralData.SerialNumber] = peripheralData + + runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralData, PeripheralStatusDisconnected) + + // If already detected, connect it + if peripheral, ok := h.peripherals[peripheralData.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") + 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") + return + } + }() + } + + // Emits the event in the hardware + runtime.EventsEmit(ctx, "LOAD_PERIPHERAL", peripheralData) + + return peripheralData.SerialNumber, nil +} + +// UnregisterPeripheral unregisters an existing peripheral +func (h *Manager) UnregisterPeripheral(ctx context.Context, peripheralData PeripheralInfo) error { + h.mu.Lock() + defer h.mu.Unlock() + + if peripheral, detected := h.peripherals[peripheralData.SerialNumber]; detected { + // Deactivating peripheral + err := peripheral.Deactivate(ctx) + if err != nil { + log.Err(err).Str("sn", peripheralData.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") + return nil + } + } + delete(h.savedPeripherals, peripheralData.SerialNumber) + runtime.EventsEmit(ctx, "UNLOAD_PERIPHERAL", peripheralData) + + return nil +} + +// GetPeripheralSettings gets the peripheral settings +func (h *Manager) GetPeripheralSettings(peripheralSN string) (map[string]any, error) { + // Return the specified peripheral + peripheral, found := h.peripherals[peripheralSN] + if !found { + // Peripheral not detected, return the last settings saved + if savedPeripheral, isFound := h.savedPeripherals[peripheralSN]; isFound { + return savedPeripheral.Settings, nil + } + return nil, fmt.Errorf("unable to found the peripheral") + } + return peripheral.GetSettings(), nil +} + +// SetPeripheralSettings sets the peripheral settings +func (h *Manager) SetPeripheralSettings(ctx context.Context, peripheralSN string, settings map[string]any) error { + peripheral, found := h.peripherals[peripheralSN] + if !found { + return fmt.Errorf("unable to found the FTDI peripheral") + } + return peripheral.SetSettings(ctx, settings) +} + // Start starts to find new peripheral events func (h *Manager) Start(ctx context.Context) error { - // Initialize all the finders and their callback functions + + // Register all the finders to use as hardware scanners h.RegisterFinder(NewFTDIFinder(3 * time.Second)) h.RegisterFinder(NewOS2LFinder()) h.RegisterFinder(NewMIDIFinder(3 * time.Second)) for finderName, finder := range h.finders { + + // Initialize the finder err := finder.Initialize() if err != nil { log.Err(err).Str("file", "hardware").Str("finderName", finderName).Msg("unable to initialize finder") return err } - finder.OnArrival(func(p PeripheralInfo) { - runtime.EventsEmit(ctx, string(PeripheralArrival), p) - }) - finder.OnRemoval(func(p PeripheralInfo) { - runtime.EventsEmit(ctx, string(PeripheralRemoval), p) - }) + + // Set callback functions + finder.OnArrival(h.OnPeripheralArrival) + finder.OnRemoval(h.OnPeripheralRemoval) + + // Start the finder err = finder.Start(ctx) if err != nil { log.Err(err).Str("file", "hardware").Str("finderName", finderName).Msg("unable to start finder") return err } } - - // Periodically scan all the finders - h.wg.Add(1) - go func() { - defer h.wg.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 } +// OnPeripheralArrival is called when a peripheral arrives in the system +func (h *Manager) OnPeripheralArrival(ctx context.Context, peripheral Peripheral) { + // Add the peripheral to the detected hardware + h.peripherals[peripheral.GetInfo().SerialNumber] = peripheral + + // If the peripheral is saved in the project, connect it + if _, saved := h.savedPeripherals[peripheral.GetInfo().SerialNumber]; saved { + h.wg.Add(1) + go func(p Peripheral) { + defer h.wg.Done() + err := p.Connect(ctx) + if err != nil { + log.Err(err).Str("sn", p.GetInfo().SerialNumber).Msg("unable to connect the FTDI peripheral") + return + } + err = p.Activate(ctx) + if err != nil { + log.Err(err).Str("sn", p.GetInfo().SerialNumber).Msg("unable to activate the FTDI peripheral") + return + } + }(peripheral) + } + + // TODO: Update the Peripheral reference in the corresponding devices + + runtime.EventsEmit(ctx, string(PeripheralArrival), peripheral.GetInfo()) +} + +// OnPeripheralRemoval is called when a peripheral exits the system +func (h *Manager) OnPeripheralRemoval(ctx context.Context, peripheral Peripheral) { + // Properly deactivating and disconnecting the peripheral + h.wg.Add(1) + go func(p Peripheral) { + defer h.wg.Done() + err := p.Deactivate(ctx) + if err != nil { + log.Err(err).Str("sn", p.GetInfo().SerialNumber).Msg("unable to deactivate peripheral after disconnection") + } + err = p.Disconnect(ctx) + if err != nil { + log.Err(err).Str("sn", p.GetInfo().SerialNumber).Msg("unable to disconnect the peripheral after disconnection") + } + }(peripheral) + + // Remove the peripheral from the hardware + delete(h.peripherals, peripheral.GetInfo().SerialNumber) + + // TODO: Update the Peripheral reference in the corresponding devices + runtime.EventsEmit(ctx, string(PeripheralRemoval), peripheral.GetInfo()) +} + // GetFinder returns a register finder func (h *Manager) GetFinder(finderName string) (PeripheralFinder, error) { finder, exists := h.finders[finderName] @@ -117,23 +237,10 @@ func (h *Manager) RegisterFinder(finder PeripheralFinder) { log.Info().Str("file", "hardware").Str("finderName", finder.GetName()).Msg("finder registered") } -// Scan scans all the peripherals for the registered finders -func (h *Manager) Scan() error { - select { - case h.peripheralsScanTrigger <- struct{}{}: - return nil - default: - return fmt.Errorf("scan trigger not available (manager stopped?)") - } -} - // WaitStop stops the hardware manager func (h *Manager) WaitStop() error { log.Trace().Str("file", "hardware").Msg("closing the hardware manager") - // Closing trigger channel - close(h.peripheralsScanTrigger) - // Stop each finder var errs []error for name, f := range h.finders { @@ -142,6 +249,15 @@ 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 { + err := registeredPeripheral.WaitStop() + if err != nil { + errs = append(errs, fmt.Errorf("%s: %w", registeredPeripheralSN, err)) + } + } + // Wait for goroutines to finish h.wg.Wait() diff --git a/hardware/interfaces.go b/hardware/interfaces.go index dc8308d..e630adf 100644 --- a/hardware/interfaces.go +++ b/hardware/interfaces.go @@ -19,13 +19,13 @@ type Device interface { // Peripheral represents the methods used to manage a peripheral (input or output hardware) type Peripheral interface { - Connect(context.Context) error // Connect the peripheral - SetEventCallback(func(any)) // Callback is called when an event is emitted from the peripheral - Disconnect(context.Context) error // Disconnect the peripheral - Activate(context.Context) error // Activate the peripheral - Deactivate(context.Context) error // Deactivate the peripheral - AddDevice(Device) error // Add a device to the peripheral - RemoveDevice(Device) error // Remove a device to the peripheral + Connect(context.Context) error // Connect the peripheral + // SetEventCallback(func(any)) // Callback is called when an event is emitted from the peripheral + Disconnect(context.Context) error // Disconnect the peripheral + Activate(context.Context) error // Activate the peripheral + Deactivate(context.Context) error // Deactivate the peripheral + // AddDevice(Device) error // Add a device to the peripheral + // RemoveDevice(Device) error // Remove a device to the peripheral GetSettings() map[string]any // Get the peripheral settings SetSettings(context.Context, map[string]any) error // Set a peripheral setting SetDeviceProperty(context.Context, uint32, byte) error // Update a device property @@ -45,15 +45,11 @@ type PeripheralInfo struct { // PeripheralFinder represents how compatible peripheral drivers are implemented type PeripheralFinder interface { - Initialize() error // Initializes the protocol - OnArrival(cb func(p PeripheralInfo)) // Callback function when a peripheral arrives - OnRemoval(cb func(p PeripheralInfo)) // Callback function when a peripheral goes away - Start(context.Context) error // Start the detection - WaitStop() error // Waiting for finder to close - ForceScan() // Explicitly scans for peripherals - RegisterPeripheral(context.Context, PeripheralInfo) (string, error) // Registers a new peripheral data - UnregisterPeripheral(context.Context, PeripheralInfo) error // Unregisters an existing peripheral - GetPeripheralSettings(string) (map[string]any, error) // Gets the peripheral settings - SetPeripheralSettings(context.Context, string, map[string]any) error // Sets the peripheral settings - GetName() string // Get the name of the finder + Initialize() error // Initializes the protocol + Create(ctx context.Context, peripheralInfo PeripheralInfo) (string, error) // Manually create a peripheral + OnArrival(cb func(context.Context, Peripheral)) // Callback function when a peripheral arrives + OnRemoval(cb func(context.Context, Peripheral)) // Callback function when a peripheral goes away + Start(context.Context) error // Start the detection + WaitStop() error // Waiting for finder to close + GetName() string // Get the name of the finder } diff --git a/peripherals.go b/peripherals.go index f9fb409..b9ad7f6 100644 --- a/peripherals.go +++ b/peripherals.go @@ -9,14 +9,8 @@ import ( // AddPeripheral adds a peripheral to the project func (a *App) AddPeripheral(peripheralData hardware.PeripheralInfo) (string, error) { - // Get the peripheral from its finder - f, err := a.hardwareManager.GetFinder(peripheralData.ProtocolName) - if err != nil { - log.Error().Str("file", "peripheral").Str("protocolName", peripheralData.ProtocolName).Msg("unable to found the specified finder") - return "", fmt.Errorf("unable to found the peripheral ID '%s'", peripheralData.SerialNumber) - } // Register this new peripheral - serialNumber, err := f.RegisterPeripheral(a.ctx, peripheralData) + serialNumber, err := a.hardwareManager.RegisterPeripheral(a.ctx, peripheralData) if err != nil { return "", fmt.Errorf("unable to register the peripheral '%s': %w", serialNumber, err) } @@ -35,25 +29,24 @@ func (a *App) AddPeripheral(peripheralData hardware.PeripheralInfo) (string, err return peripheralData.SerialNumber, nil } -// GetPeripheralSettings gets the peripheral settings -func (a *App) GetPeripheralSettings(protocolName, peripheralID string) (map[string]any, error) { - // Get the peripheral from its finder - f, err := a.hardwareManager.GetFinder(protocolName) +// CreatePeripheral creates a new peripheral +func (a *App) CreatePeripheral(peripheralData hardware.PeripheralInfo) (string, error) { + // Get the appropriate finder to create the device + finder, err := a.hardwareManager.GetFinder(peripheralData.ProtocolName) if err != nil { - log.Error().Str("file", "peripheral").Str("protocolName", protocolName).Str("periphID", peripheralID).Msg("unable to found the specified peripheral") - return nil, fmt.Errorf("unable to found the peripheral ID '%s'", peripheralID) + return "", fmt.Errorf("unable to find the appropriate finder (%s): %w", peripheralData.ProtocolName, err) } - return f.GetPeripheralSettings(peripheralID) + // Manually create the peripheral from its finder + return finder.Create(a.ctx, peripheralData) +} + +// GetPeripheralSettings gets the peripheral settings +func (a *App) GetPeripheralSettings(protocolName, peripheralSN string) (map[string]any, error) { + return a.hardwareManager.GetPeripheralSettings(peripheralSN) } // UpdatePeripheralSettings updates a specific setting of a peripheral func (a *App) UpdatePeripheralSettings(protocolName, peripheralID string, settings map[string]any) error { - // Sets the settings with the finder - f, err := a.hardwareManager.GetFinder(protocolName) - if err != nil { - log.Error().Str("file", "peripheral").Str("protocolName", protocolName).Str("periphID", peripheralID).Msg("unable to found the specified peripheral") - return fmt.Errorf("unable to found the peripheral ID '%s'", peripheralID) - } // Save the settings in the application if a.projectInfo.PeripheralsInfo == nil { a.projectInfo.PeripheralsInfo = make(map[string]hardware.PeripheralInfo) @@ -62,65 +55,18 @@ func (a *App) UpdatePeripheralSettings(protocolName, peripheralID string, settin pInfo.Settings = settings a.projectInfo.PeripheralsInfo[peripheralID] = pInfo // Apply changes in the peripheral - return f.SetPeripheralSettings(a.ctx, peripheralID, pInfo.Settings) + return a.hardwareManager.SetPeripheralSettings(a.ctx, peripheralID, pInfo.Settings) } // RemovePeripheral removes a peripheral from the project func (a *App) RemovePeripheral(peripheralData hardware.PeripheralInfo) error { // Unregister the peripheral from the finder - f, err := a.hardwareManager.GetFinder(peripheralData.ProtocolName) + err := a.hardwareManager.UnregisterPeripheral(a.ctx, peripheralData) if err != nil { - log.Err(err).Str("file", "peripherals").Str("protocolName", peripheralData.ProtocolName).Msg("unable to find the finder") - return fmt.Errorf("unable to find the finder") - } - err = f.UnregisterPeripheral(a.ctx, peripheralData) - if err != nil { - log.Err(err).Str("file", "peripherals").Str("peripheralID", peripheralData.SerialNumber).Msg("unable to unregister this peripheral") - return fmt.Errorf("unable to unregister this peripheral") + return fmt.Errorf("unable to unregister this peripheral: %w", err) } // Remove the peripheral ID from the project delete(a.projectInfo.PeripheralsInfo, peripheralData.SerialNumber) log.Info().Str("file", "peripheral").Str("protocolName", peripheralData.ProtocolName).Str("periphID", peripheralData.SerialNumber).Msg("peripheral removed from project") return nil } - -// FOR TESTING PURPOSE ONLY - -// func (a *App) ActivateFTDI() error { -// // Connect the FTDI -// driver, err := a.hardwareManager.GetFinder("FTDI") -// if err != nil { -// return err -// } -// periph, found := driver.GetPeripheral("A50285BI") -// if !found { -// return fmt.Errorf("unable to find the peripheral s/n %s", "A50285BI") -// } -// return periph.Activate(a.ctx) -// } - -// func (a *App) SetDeviceFTDI(channelValue byte) error { -// // Connect the FTDI -// driver, err := a.hardwareManager.GetFinder("FTDI") -// if err != nil { -// return err -// } -// periph, found := driver.GetPeripheral("A50285BI") -// if !found { -// return fmt.Errorf("unable to find the peripheral s/n %s", "A50285BI") -// } -// return periph.SetDeviceProperty(a.ctx, 0, 0, channelValue) -// } - -// func (a *App) DeactivateFTDI() error { -// // Connect the FTDI -// driver, err := a.hardwareManager.GetFinder("FTDI") -// if err != nil { -// return err -// } -// periph, found := driver.GetPeripheral("A50285BI") -// if !found { -// return fmt.Errorf("unable to find the peripheral s/n %s", "A50285BI") -// } -// return periph.Deactivate(a.ctx) -// } diff --git a/project.go b/project.go index 9b9954d..be227d2 100644 --- a/project.go +++ b/project.go @@ -130,11 +130,7 @@ func (a *App) OpenProject(projectInfo ProjectInfo) error { // Load all peripherals of the project projectPeripherals := a.projectInfo.PeripheralsInfo for key, value := range projectPeripherals { - hostFinder, err := a.hardwareManager.GetFinder(value.ProtocolName) - if err != nil { - return fmt.Errorf("unable to find the finder '%s': %w", value.ProtocolName, err) - } - _, err = hostFinder.RegisterPeripheral(a.ctx, value) + _, err = a.hardwareManager.RegisterPeripheral(a.ctx, value) if err != nil { return fmt.Errorf("unable to register the peripheral S/N '%s': %w", key, err) } @@ -147,11 +143,7 @@ func (a *App) CloseCurrentProject() error { // Unregistrer all peripherals of the project projectPeripherals := a.projectInfo.PeripheralsInfo for key, value := range projectPeripherals { - hostFinder, err := a.hardwareManager.GetFinder(value.ProtocolName) - if err != nil { - return fmt.Errorf("unable to find the finder '%s': %w", value.ProtocolName, err) - } - err = hostFinder.UnregisterPeripheral(a.ctx, value) + err := a.hardwareManager.UnregisterPeripheral(a.ctx, value) if err != nil { return fmt.Errorf("unable to unregister the peripheral S/N '%s': %w", key, err) }