+
{#if status == "PERIPHERAL_DISCONNECTED" } {/if}{title}
{type} {location != '' ? "- " : ""}{location}
@@ -52,8 +52,8 @@
-
-
+
+
@@ -63,19 +63,33 @@
background: linear-gradient(to bottom right, var(--second-color), var(--third-color));
}
.card{
- position: relative;
+ position: relative;
}
.selected {
- background-color: var(--first-color);
+ background-color: var(--third-color);
+ position: relative;
margin: 0.2em;
- padding-left: 0.3em;
- padding-bottom: 0.3em;
- border-radius: 0.2em;
+ padding: 0.2em 0.3em 0.5em 0.5em;
+ border-radius: 0.5em;
display: flex;
justify-content: space-between;
text-align: left;
cursor: pointer;
+ overflow: hidden;
}
+ .unselected{
+ background-color: var(--second-color);
+ position: relative;
+ margin: 0.2em;
+ padding: 0.2em 0.3em 0.5em 0.5em;
+ border-radius: 0.5em;
+ display: flex;
+ justify-content: space-between;
+ text-align: left;
+ cursor: pointer;
+ overflow: hidden;
+ }
+
.subtitle{
margin-bottom: 0.5em;
}
@@ -94,7 +108,7 @@
.waiting::before{
content: '';
position: absolute;
- background: linear-gradient(var(--second-color), var(--first-color));
+ background: linear-gradient(var(--first-color), var(--second-color));
width: 100%;
height: 60%;
animation: rotate 3s linear infinite;
@@ -108,21 +122,6 @@
border-radius: 0.2em;
}
- .unselected{
- background-color: var(--third-color);
- background: fixed;
- position: relative;
- margin: 0.2em;
- padding-left: 0.3em;
- padding-bottom: 0.3em;
- border-radius: 0.2em;
- display: flex;
- justify-content: space-between;
- text-align: left;
- cursor: pointer;
- overflow: hidden;
- }
-
/* Définition de l'animation */
@keyframes rotate {
from {
diff --git a/frontend/src/components/Settings/InputsOutputsContent.svelte b/frontend/src/components/Settings/InputsOutputsContent.svelte
index a8373a4..f67b102 100644
--- a/frontend/src/components/Settings/InputsOutputsContent.svelte
+++ b/frontend/src/components/Settings/InputsOutputsContent.svelte
@@ -1,9 +1,8 @@
-
-
{$_("projectHardwareAvailableLabel")}
+
-
{$_("projectHardwareDetectedLabel")}
- {#each Object.entries($peripherals) as [serialNumber, peripheral]}
- {#if peripheral.isDetected}
-
addPeripheral(peripheral)} on:dblclick={() => {
- if(!peripheral.isSaved)
- addPeripheral(peripheral)
- }}
- status="PERIPHERAL_CONNECTED" title={peripheral.Name} type={peripheral.ProtocolName} location={peripheral.Location ? peripheral.Location : ""} line1={"S/N: " + peripheral.SerialNumber} addable={!peripheral.isSaved}/>
- {/if}
- {/each}
- {$_("projectHardwareOthersLabel")}
- addPeripheral({Name: "OS2L connection", ProtocolName: "OS2L"})} text="Add an OS2L peripheral" icon="bx-plus-circle" tooltip="Configure an OS2L connection"/>
+ {$_("projectHardwareDetectedLabel")}
+ {#each Object.entries($peripherals) as [serialNumber, peripheral]}
+ {#if peripheral.isDetected}
+
addPeripheral(peripheral)} on:dblclick={() => {
+ if(!peripheral.isSaved)
+ addPeripheral(peripheral)
+ }}
+ status="PERIPHERAL_CONNECTED" title={peripheral.Name} type={peripheral.ProtocolName} location={peripheral.Location ? peripheral.Location : ""} line1={"S/N: " + peripheral.SerialNumber} addable={!peripheral.isSaved}/>
+ {/if}
+ {/each}
+
+
{$_("projectHardwareOthersLabel")}
+
+ addPeripheral({Name: "OS2L virtual device", ProtocolName: "OS2L", SerialNumber: ""})}
+ on:dblclick={() => addPeripheral({Name: "OS2L virtual device", ProtocolName: "OS2L", SerialNumber: ""})}
+ status="PERIPHERAL_CONNECTED" title={"OS2L virtual device"} type={"OS2L"} location={""} addable={true}/>
@@ -104,14 +106,13 @@
{#each Object.entries($peripherals) as [serialNumber, peripheral]}
{#if peripheral.isSaved}
removePeripheral(peripheral)} on:dblclick={() => removePeripheral(peripheral)} on:click={() => selectPeripheral(peripheral)}
- title={peripheral.Name} type={peripheral.ProtocolName} location={peripheral.Location ? peripheral.Location : ""} line1={peripheral.SerialNumber ? "S/N: " + peripheral.SerialNumber : ""} selected={serialNumber == selectedPeripheralSN} removable signalizable/>
+ title={peripheral.Name} type={peripheral.ProtocolName} location={peripheral.Location ? peripheral.Location : ""} line1={peripheral.SerialNumber ? "S/N: " + peripheral.SerialNumber : ""} selected={serialNumber == selectedPeripheralSN} removable signalizable signalized={peripheral.eventEmitted}/>
{/if}
{/each}
{:else}
{$_("projectHardwareEmptyLabel")}
{/if}
-
{$_("projectHardwareSettingsLabel")} ({selectedPeripheralSN == null ? $_("projectHardwareNoSelection") : selectedPeripheralSN})
{#if Object.keys(selectedPeripheralSettings).length > 0}
{#each Object.entries(selectedPeripheralSettings) as [settingName, settingValue]}
@@ -119,8 +120,6 @@
validate(settingName, event.detail.target.value)} label={$t(settingName)} type="{typeof(settingValue)}" width='100%' value="{settingValue}"/>
{/each}
- {:else}
-
{$_("projectHardwareNoSettingLabel")}
{/if}
@@ -149,19 +148,23 @@
border-radius: 0.5em;
padding: 0.2em;
max-height: calc(100vh - 300px);
- overflow-y: auto;
- scrollbar-width: none; /* Firefox */
- -ms-overflow-style: none; /* IE and Edge */
- /* overflow: visible; */
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
}
- .availableHardware::-webkit-scrollbar {
- display: none;
- }
- .configuredHardware {
- background-color: var(--second-color);
- border-radius: 0.5em;
+
+ .libraryPanel {
padding: 0.5em;
- padding: 0.2em;
+ /* width: 13em; */
+ height: calc(100vh - 2*8px - 2*4px - 40px - 1em - 2*0.1em - 2*0.1em - 2*0.4em - 21.6px - 2*0.5em);
+ overflow: auto;
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+ }
+ .libraryPanel::-webkit-scrollbar {
+ display: none; /* Chrome, Safari, Edge */
+ }
+
+ .configuredHardware {
display: flex;
flex-wrap: wrap;
}
diff --git a/frontend/src/components/Settings/Settings.svelte b/frontend/src/components/Settings/Settings.svelte
index 9625ecb..a1fb30d 100644
--- a/frontend/src/components/Settings/Settings.svelte
+++ b/frontend/src/components/Settings/Settings.svelte
@@ -12,7 +12,7 @@
-
+
\ No newline at end of file
diff --git a/frontend/src/lang/en.json b/frontend/src/lang/en.json
index f185eb7..f153022 100644
--- a/frontend/src/lang/en.json
+++ b/frontend/src/lang/en.json
@@ -13,6 +13,7 @@
"newProjectTooltip": "Create a new project",
"openProjectString": "Open",
"openProjectTooltip": "Open an existing project",
+ "openProjectEmpty": "No project found",
"unsavedProjectFlag": "unsaved",
"projectPropertiesTab": "Project properties",
"projectPropertiesTooltip": "The project properties",
@@ -34,16 +35,13 @@
"projectHardwareShowLabel" : "My Show",
"projectHardwareInputsLabel": "INPUTS",
"projectHardwareOutputsLabel": "OUTPUTS",
- "projectHardwareDeleteTooltip": "Delete this peripheral",
- "projectHardwareAddTooltip": "Add this peripheral to project",
+ "projectHardwareDeleteTooltip": "Delete",
+ "projectHardwareAddTooltip": "Add to project",
"projectHardwareNoSelection": "Empty",
- "projectHardwareAvailableLabel": "Available peripherals",
- "projectHardwareSavedLabel": "Project peripherals",
+ "projectHardwareSavedLabel": "Saved in project",
"projectHardwareDetectedLabel": "Detected",
"projectHardwareOthersLabel": "Others",
"projectHardwareEmptyLabel": "No hardware saved for this project",
- "projectHardwareSettingsLabel": "Peripheral settings",
- "projectHardwareNoSettingLabel": "No setting can be displayed",
"peripheralArrivalToast": "Peripheral inserted:",
"peripheralRemovalToast": "Peripheral removed:",
diff --git a/frontend/src/runtime-events.js b/frontend/src/runtime-events.js
index 59a290b..d509a83 100644
--- a/frontend/src/runtime-events.js
+++ b/frontend/src/runtime-events.js
@@ -120,6 +120,32 @@ function unloadPeripheral (peripheralInfo) {
needProjectSave.set(true)
}
+// A peripheral event has been emitted
+function onPeripheralEvent(sn, event) {
+ // If not exists, add it to the map
+ // eventEmitted key to true for 0.2 sec
+
+ peripherals.update((storedPeripherals) => {
+ return {
+ ...storedPeripherals,
+ [sn]: {
+ ...storedPeripherals[sn],
+ eventEmitted: true
+ },
+ }})
+
+ setTimeout(() => {
+ peripherals.update((storedPeripherals) => {
+ return {
+ ...storedPeripherals,
+ [sn]: {
+ ...storedPeripherals[sn],
+ eventEmitted: false
+ },
+ }})
+ }, 200);
+}
+
let initialized = false
export function initRuntimeEvents(){
@@ -143,6 +169,9 @@ export function initRuntimeEvents(){
// Handle a peripheral unloaded from the project
EventsOn('UNLOAD_PERIPHERAL', unloadPeripheral)
+
+ // Handle a peripheral event
+ EventsOn('PERIPHERAL_EVENT_EMITTED', onPeripheralEvent)
}
export function destroyRuntimeEvents(){
@@ -166,4 +195,7 @@ export function destroyRuntimeEvents(){
// Handle a peripheral unloaded from the project
EventsOff('UNLOAD_PERIPHERAL')
+
+ // Handle a peripheral event
+ EventsOff('PERIPHERAL_EVENT_EMITTED')
}
\ No newline at end of file
diff --git a/frontend/src/stores.js b/frontend/src/stores.js
index 02aeb53..984a346 100644
--- a/frontend/src/stores.js
+++ b/frontend/src/stores.js
@@ -45,4 +45,5 @@ export let peripherals = writable({})
// isSaved // if the peripheral is saved in the project
// isDetected // if the peripheral is detected by the system
-// status // the status of connection
\ No newline at end of file
+// status // the status of connection
+// eventEmitted // if an event has been emitted for this peripheral (disappear after a delay)
\ No newline at end of file
diff --git a/hardware/FTDIFinder.go b/hardware/FTDIFinder.go
index 2fc2e5b..b620730 100644
--- a/hardware/FTDIFinder.go
+++ b/hardware/FTDIFinder.go
@@ -2,6 +2,7 @@ package hardware
import (
"context"
+ "errors"
"fmt"
goRuntime "runtime"
"sync"
@@ -59,24 +60,25 @@ func (f *FTDIFinder) RegisterPeripheral(ctx context.Context, peripheralData Peri
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 {
- runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralData, PeripheralStatusConnecting)
- err := peripheral.Connect(ctx)
- if err != nil {
- runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralData, PeripheralStatusDisconnected)
- log.Err(err).Str("file", "FTDIFinder").Str("peripheralSN", peripheralData.SerialNumber).Msg("unable to connect the peripheral")
- return peripheralData.SerialNumber, nil
- }
- runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralData, PeripheralStatusDeactivated)
- // 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 peripheralData.SerialNumber, nil
- }
- runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralData, PeripheralStatusActivated)
+ 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
@@ -97,14 +99,12 @@ func (f *FTDIFinder) UnregisterPeripheral(ctx context.Context, peripheralData Pe
log.Err(err).Str("sn", peripheralData.SerialNumber).Msg("unable to deactivate the peripheral")
return nil
}
- runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralData, PeripheralStatusDeactivated)
// Disconnecting peripheral
- err = peripheral.Disconnect()
+ err = peripheral.Disconnect(ctx)
if err != nil {
log.Err(err).Str("sn", peripheralData.SerialNumber).Msg("unable to disconnect the peripheral")
return nil
}
- runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralData, PeripheralStatusDisconnected)
}
delete(f.saved, peripheralData.SerialNumber)
runtime.EventsEmit(ctx, "UNLOAD_PERIPHERAL", peripheralData)
@@ -164,27 +164,28 @@ func (f *FTDIFinder) GetName() string {
// GetPeripheralSettings gets the peripheral settings
func (f *FTDIFinder) GetPeripheralSettings(peripheralID string) (map[string]interface{}, error) {
// Return the specified peripheral
- // peripheral, found := f.registeredPeripherals[peripheralID]
- // if !found {
- // log.Error().Str("file", "FTDIFinder").Str("peripheralID", peripheralID).Msg("unable to get this peripheral from the FTDI finder")
- // return nil, fmt.Errorf("unable to found the peripheral")
- // }
- // log.Debug().Str("file", "FTDIFinder").Str("peripheralID", peripheralID).Msg("peripheral found by the FTDI finder")
- // return peripheral.GetSettings(), nil
- return make(map[string]interface{}), nil
+ 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")
+ }
+ log.Debug().Str("file", "FTDIFinder").Str("peripheralID", peripheralID).Msg("peripheral found by the FTDI finder")
+ return peripheral.GetSettings(), nil
}
// SetPeripheralSettings sets the peripheral settings
-func (f *FTDIFinder) SetPeripheralSettings(peripheralID string, settings map[string]interface{}) error {
+func (f *FTDIFinder) SetPeripheralSettings(ctx context.Context, peripheralID string, settings map[string]any) error {
// Return the specified peripheral
- // peripheral, found := f.registeredPeripherals[peripheralID]
- // if !found {
- // log.Error().Str("file", "FTDIFinder").Str("peripheralID", peripheralID).Msg("unable to get this peripheral from the FTDI finder")
- // return fmt.Errorf("unable to found the peripheral")
- // }
- // log.Debug().Str("file", "FTDIFinder").Str("peripheralID", peripheralID).Msg("peripheral found by the FTDI finder")
- // return peripheral.SetSettings(settings)
- return nil
+ peripheral, found := f.detected[peripheralID]
+ if !found {
+ log.Error().Str("file", "FTDIFinder").Str("peripheralID", peripheralID).Msg("unable to get this peripheral from the FTDI finder")
+ return fmt.Errorf("unable to found the 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
@@ -233,29 +234,26 @@ func (f *FTDIFinder) scanPeripherals(ctx context.Context) error {
f.detected[sn] = peripheral
if f.onArrival != nil {
- go f.onArrival(peripheralData)
+ f.onArrival(peripheralData)
}
log.Info().Str("sn", sn).Str("name", peripheralData.Name).Msg("[FTDI] New peripheral detected")
- // Disconnected by default
- runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralData, PeripheralStatusDisconnected)
-
// If the peripheral is saved in the project => connect
if _, saved := f.saved[sn]; saved {
- runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralData, PeripheralStatusConnecting)
- err := peripheral.Connect(ctx)
- if err != nil {
- runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralData, PeripheralStatusDisconnected)
- log.Err(err).Str("sn", sn).Msg("unable to connect the FTDI peripheral")
- return nil
- }
- runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralData, PeripheralStatusDeactivated)
- err = peripheral.Activate(ctx)
- if err != nil {
- log.Err(err).Str("sn", sn).Msg("unable to activate the FTDI peripheral")
- return nil
- }
- runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralData, PeripheralStatusActivated)
+ 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)
}
}
}
@@ -265,11 +263,14 @@ func (f *FTDIFinder) scanPeripherals(ctx context.Context) error {
if _, still := currentMap[sn]; !still {
// Properly clean the DMX device
- err := oldPeripheral.Disconnect()
+ err := oldPeripheral.Deactivate(ctx)
if err != nil {
- log.Err(err).Str("sn", sn).Msg("unable to clean the FTDI peripheral after disconnection")
+ 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")
}
- runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), oldPeripheral.GetInfo(), PeripheralStatusDisconnected)
// Delete it from the detected list
delete(f.detected, sn)
@@ -277,7 +278,7 @@ func (f *FTDIFinder) scanPeripherals(ctx context.Context) error {
// Execute the removal callback
if f.onRemoval != nil {
- go f.onRemoval(oldPeripheral.GetInfo())
+ f.onRemoval(oldPeripheral.GetInfo())
}
}
}
@@ -292,22 +293,22 @@ func (f *FTDIFinder) WaitStop() error {
// 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.registeredPeripherals {
- // err := registeredPeripheral.WaitStop()
- // if err != nil {
- // errs = append(errs, fmt.Errorf("%s: %w", registeredPeripheralSN, err))
- // }
- // }
+ 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...)
- // }
+ 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 8debace..ac9a088 100644
--- a/hardware/FTDIPeripheral.go
+++ b/hardware/FTDIPeripheral.go
@@ -8,6 +8,7 @@ import (
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
+ "github.com/wailsapp/wails/v2/pkg/runtime"
)
/*
@@ -41,6 +42,8 @@ func (p *FTDIPeripheral) Connect(ctx context.Context) error {
return errors.Errorf("the DMX device has already been created!")
}
+ runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), p.GetInfo(), PeripheralStatusConnecting)
+
// Create the DMX sender
p.dmxSender = C.dmx_create()
@@ -48,6 +51,7 @@ func (p *FTDIPeripheral) Connect(ctx context.Context) error {
serialNumber := C.CString(p.info.SerialNumber)
defer C.free(unsafe.Pointer(serialNumber))
if C.dmx_connect(p.dmxSender, serialNumber) != C.DMX_OK {
+ runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), p.GetInfo(), PeripheralStatusDisconnected)
log.Error().Str("file", "FTDIPeripheral").Str("s/n", p.info.SerialNumber).Msg("unable to connect the DMX device")
return errors.Errorf("unable to connect '%s'", p.info.SerialNumber)
}
@@ -56,15 +60,16 @@ func (p *FTDIPeripheral) Connect(ctx context.Context) error {
go func() {
defer p.wg.Done()
<-ctx.Done()
- _ = p.Disconnect()
+ _ = p.Disconnect(ctx)
}()
+ runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), p.GetInfo(), PeripheralStatusDeactivated)
log.Trace().Str("file", "FTDIPeripheral").Str("s/n", p.info.SerialNumber).Msg("DMX device connected successfully")
return nil
}
// Disconnect disconnects the FTDI peripheral
-func (p *FTDIPeripheral) Disconnect() error {
+func (p *FTDIPeripheral) Disconnect(ctx context.Context) error {
// Check if the device has already been created
if p.dmxSender == nil {
return errors.Errorf("the DMX device has not been connected!")
@@ -75,6 +80,8 @@ func (p *FTDIPeripheral) Disconnect() error {
// Reset the pointer to the peripheral
p.dmxSender = nil
+
+ runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), p.GetInfo(), PeripheralStatusDisconnected)
return nil
}
@@ -96,6 +103,8 @@ func (p *FTDIPeripheral) Activate(ctx context.Context) error {
C.dmx_setValue(p.dmxSender, C.uint16_t(1), C.uint8_t(255))
C.dmx_setValue(p.dmxSender, C.uint16_t(5), C.uint8_t(255))
+ runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), p.GetInfo(), PeripheralStatusActivated)
+
log.Trace().Str("file", "FTDIPeripheral").Str("s/n", p.info.SerialNumber).Msg("DMX device activated successfully")
return nil
}
@@ -114,6 +123,7 @@ func (p *FTDIPeripheral) Deactivate(ctx context.Context) error {
return errors.Errorf("unable to deactivate the DMX sender!")
}
+ runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), p.GetInfo(), PeripheralStatusDeactivated)
log.Trace().Str("file", "FTDIPeripheral").Str("s/n", p.info.SerialNumber).Msg("DMX device deactivated successfully")
return nil
}
diff --git a/hardware/OS2LFinder.go b/hardware/OS2LFinder.go
index 24a8d42..26d534d 100644
--- a/hardware/OS2LFinder.go
+++ b/hardware/OS2LFinder.go
@@ -2,23 +2,32 @@ package hardware
import (
"context"
+ "errors"
"fmt"
"math/rand"
"strings"
+ "sync"
"github.com/rs/zerolog/log"
+ "github.com/wailsapp/wails/v2/pkg/runtime"
)
// OS2LFinder represents how the protocol is defined
type OS2LFinder struct {
- registeredPeripherals map[string]OS2LPeripheral // The list of found peripherals
+ wg sync.WaitGroup
+ mu sync.Mutex
+
+ saved 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
}
// NewOS2LFinder creates a new OS2L finder
func NewOS2LFinder() *OS2LFinder {
log.Trace().Str("file", "OS2LFinder").Msg("OS2L finder created")
return &OS2LFinder{
- registeredPeripherals: make(map[string]OS2LPeripheral),
+ saved: make(map[string]*OS2LPeripheral),
}
}
@@ -28,37 +37,92 @@ func (f *OS2LFinder) Initialize() error {
return nil
}
+// OnArrival is the callback function when a new peripheral arrives
+func (f *OS2LFinder) OnArrival(cb func(p PeripheralInfo)) {
+ f.onArrival = cb
+}
+
+// OnRemoval i the callback when a peripheral goes away
+func (f *OS2LFinder) OnRemoval(cb func(p PeripheralInfo)) {
+ f.onRemoval = cb
+}
+
// RegisterPeripheral registers a new peripheral
func (f *OS2LFinder) RegisterPeripheral(ctx context.Context, peripheralData PeripheralInfo) (string, error) {
- // Create a random serial number for this peripheral
- peripheralData.SerialNumber = strings.ToUpper(fmt.Sprintf("%08x", rand.Intn(1<<32)))
+ f.mu.Lock()
+ defer f.mu.Unlock()
+
+ // If the SerialNumber is empty, generate another one
+ if peripheralData.SerialNumber == "" {
+ peripheralData.SerialNumber = strings.ToUpper(fmt.Sprintf("%08x", rand.Intn(1<<32)))
+ }
+
+ // Create a new OS2L peripheral
+ peripheral, err := NewOS2LPeripheral(peripheralData)
+ 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)
+ })
+
+ f.saved[peripheralData.SerialNumber] = peripheral
log.Trace().Str("file", "OS2LFinder").Str("serialNumber", peripheralData.SerialNumber).Msg("OS2L peripheral created")
- os2lPeripheral, err := NewOS2LPeripheral(peripheralData)
- if err != nil {
- return "", fmt.Errorf("unable to create the OS2L peripheral: %v", err)
- }
- // Connect this peripheral
- err = os2lPeripheral.Connect(ctx)
- if err != nil {
- return "", err
+ // New OS2L peripheral has arrived
+ if f.onArrival != nil {
+ f.onArrival(peripheral.GetInfo())
}
- f.registeredPeripherals[peripheralData.SerialNumber] = *os2lPeripheral
- log.Trace().Any("periph", &os2lPeripheral).Str("file", "OS2LFinder").Str("peripheralName", peripheralData.Name).Msg("OS2L peripheral has been created")
+ 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
}
// UnregisterPeripheral unregisters an existing peripheral
-func (f *OS2LFinder) UnregisterPeripheral(peripheralID string) error {
- peripheral, registered := f.registeredPeripherals[peripheralID]
- if registered {
- err := peripheral.Disconnect()
+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 {
- return err
+ 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.registeredPeripherals, peripheralID)
+
+ // The OS2L peripheral has gone
+ f.onRemoval(peripheralData)
+
+ delete(f.saved, peripheralData.SerialNumber)
+ runtime.EventsEmit(ctx, "UNLOAD_PERIPHERAL", peripheralData)
return nil
}
@@ -68,9 +132,9 @@ func (f *OS2LFinder) GetName() string {
}
// GetPeripheralSettings gets the peripheral settings
-func (f *OS2LFinder) GetPeripheralSettings(peripheralID string) (map[string]interface{}, error) {
+func (f *OS2LFinder) GetPeripheralSettings(peripheralID string) (map[string]any, error) {
// Return the specified peripheral
- peripheral, found := f.registeredPeripherals[peripheralID]
+ 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")
@@ -80,24 +144,49 @@ func (f *OS2LFinder) GetPeripheralSettings(peripheralID string) (map[string]inte
}
// SetPeripheralSettings sets the peripheral settings
-func (f *OS2LFinder) SetPeripheralSettings(peripheralID string, settings map[string]interface{}) error {
+func (f *OS2LFinder) SetPeripheralSettings(ctx context.Context, peripheralID string, settings map[string]any) error {
// Return the specified peripheral
- peripheral, found := f.registeredPeripherals[peripheralID]
+ peripheral, found := f.saved[peripheralID]
if !found {
log.Error().Str("file", "OS2LFinder").Str("peripheralID", peripheralID).Msg("unable to get this peripheral from the FTDI finder")
return fmt.Errorf("unable to found the peripheral")
}
- log.Debug().Str("file", "OS2LFinder").Str("peripheralID", peripheralID).Msg("peripheral found by the FTDI finder")
- return peripheral.SetSettings(settings)
+
+ // 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
return nil
}
-// Stop stops this finder
-func (f *OS2LFinder) Stop() error {
+// WaitStop stops the finder
+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
}
diff --git a/hardware/OS2LPeripheral.go b/hardware/OS2LPeripheral.go
index 4bc9703..ee17343 100644
--- a/hardware/OS2LPeripheral.go
+++ b/hardware/OS2LPeripheral.go
@@ -2,86 +2,260 @@ package hardware
import (
"context"
+ "encoding/json"
"fmt"
+ "net"
+ "strings"
+ "sync"
"time"
"github.com/rs/zerolog/log"
"github.com/wailsapp/wails/v2/pkg/runtime"
)
+// OS2LMessage represents an OS2L message
+type OS2LMessage struct {
+ Event string `json:"evt"`
+ Name string `json:"name"`
+ State string `json:"state"`
+ ID int64 `json:"id"`
+ Param float64 `json:"param"`
+}
+
// OS2LPeripheral contains the data of an OS2L peripheral
type OS2LPeripheral struct {
- info PeripheralInfo // The basic info for this peripheral
- serverIP string // OS2L server IP
- serverPort int // OS2L server port
+ wg sync.WaitGroup
+
+ info PeripheralInfo // The basic info for this peripheral
+ serverIP string // OS2L server IP
+ serverPort int // OS2L server port
+ listener net.Listener // Net listener (TCP)
+ listenerCancel context.CancelFunc // Call this function to cancel the peripheral activation
+
+ eventCallback func(any) // This callback is called for returning events
}
// NewOS2LPeripheral creates a new OS2L peripheral
func NewOS2LPeripheral(peripheralData PeripheralInfo) (*OS2LPeripheral, error) {
+ peripheral := &OS2LPeripheral{
+ info: peripheralData,
+ listener: nil,
+ eventCallback: nil,
+ }
log.Trace().Str("file", "OS2LPeripheral").Str("name", peripheralData.Name).Str("s/n", peripheralData.SerialNumber).Msg("OS2L peripheral created")
- return &OS2LPeripheral{
- info: peripheralData,
- serverIP: "127.0.0.1",
- serverPort: 9005,
- }, nil
+ return peripheral, peripheral.loadSettings(peripheralData.Settings)
}
-// Connect connects the MIDI peripheral
+// SetEventCallback sets the callback for returning events
+func (p *OS2LPeripheral) SetEventCallback(eventCallback func(any)) {
+ p.eventCallback = eventCallback
+}
+
+// Connect connects the OS2L peripheral
func (p *OS2LPeripheral) Connect(ctx context.Context) error {
+ runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), p.GetInfo(), PeripheralStatusConnecting)
+
+ var err error
+ addr := net.TCPAddr{Port: p.serverPort, IP: net.ParseIP(p.serverIP)}
+
+ log.Debug().Any("addr", addr).Msg("parametres de connexion à la connexion")
+ p.listener, err = net.ListenTCP("tcp", &addr)
+ if err != nil {
+ runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), p.GetInfo(), PeripheralStatusDisconnected)
+ return fmt.Errorf("unable to set the OS2L TCP listener")
+ }
+
+ runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), p.GetInfo(), PeripheralStatusDeactivated)
log.Info().Str("file", "OS2LPeripheral").Msg("OS2L peripheral connected")
- go func() {
- runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), p.info, "connecting")
- time.Sleep(5 * time.Second)
- runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), p.info, "disconnected")
- }()
return nil
}
-// Disconnect disconnects the MIDI peripheral
-func (p *OS2LPeripheral) Disconnect() error {
- log.Info().Str("file", "OS2LPeripheral").Msg("OS2L peripheral disconnected")
+// handleMessage handles an OS2L message
+func (p *OS2LPeripheral) handleMessage(raw []byte) error {
+ message := OS2LMessage{}
+ err := json.Unmarshal(raw, &message)
+ if err != nil {
+ return fmt.Errorf("Unable to parse the OS2L message: %w", err)
+ }
+ log.Debug().Str("event", message.Event).Str("name", message.Name).Str("state", message.State).Int("ID", int(message.ID)).Float64("param", message.Param).Msg("OS2L event received")
+ // Return the event to the finder
+ if p.eventCallback != nil {
+ go p.eventCallback(message)
+ }
return nil
}
-// Activate activates the MIDI peripheral
-func (p *OS2LPeripheral) Activate(ctx context.Context) error {
- log.Info().Str("file", "OS2LPeripheral").Msg("OS2L peripheral activated")
- return nil
-}
-
-// Deactivate deactivates the MIDI peripheral
-func (p *OS2LPeripheral) Deactivate(ctx context.Context) error {
- log.Info().Str("file", "OS2LPeripheral").Msg("OS2L peripheral deactivated")
- return nil
-}
-
-// SetSettings sets a specific setting for this peripheral
-func (p *OS2LPeripheral) SetSettings(settings map[string]interface{}) error {
+// loadSettings check and load the settings in the peripheral
+func (p *OS2LPeripheral) loadSettings(settings map[string]any) error {
// Check if the IP exists
serverIP, found := settings["os2lIp"]
if !found {
- return fmt.Errorf("Unable to find the OS2L server IP")
+ // Set default IP address
+ serverIP = "127.0.0.1"
}
// Check if it is a string
ipSetting, ok := serverIP.(string)
if ok {
p.serverIP = ipSetting
-
} else {
return fmt.Errorf("The specified IP is not a string")
}
// Check if the port exists
serverPort, found := settings["os2lPort"]
if !found {
- return fmt.Errorf("Unable to find the OS2L server port")
+ // Set default port
+ serverPort = 9995
}
- // Check if it is a float and convert to int
- portFloat, ok := serverPort.(float64)
- if ok {
- p.serverPort = int(portFloat)
- } else {
- return fmt.Errorf("The specified port is not an int")
+ switch v := serverPort.(type) {
+ case int:
+ p.serverPort = v
+ case float64:
+ p.serverPort = int(v) // JSON numbers are float64
+ default:
+ return fmt.Errorf("The specified port is not a number, got %T", serverPort)
}
+
+ return nil
+}
+
+// Disconnect disconnects the MIDI peripheral
+func (p *OS2LPeripheral) Disconnect(ctx context.Context) error {
+
+ // Close the TCP listener if not null
+ if p.listener != nil {
+ p.listener.Close()
+ }
+
+ runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), p.GetInfo(), PeripheralStatusDisconnected)
+
+ log.Info().Str("file", "OS2LPeripheral").Msg("OS2L peripheral disconnected")
+ return nil
+}
+
+// Activate activates the OS2L peripheral
+func (p *OS2LPeripheral) Activate(ctx context.Context) error {
+ // Create a derived context to handle deactivation
+ var listenerCtx context.Context
+ listenerCtx, p.listenerCancel = context.WithCancel(ctx)
+
+ if p.listener == nil {
+ return fmt.Errorf("the listener isn't defined")
+ }
+
+ p.wg.Add(1)
+ go func() {
+ defer p.wg.Done()
+
+ for {
+ select {
+ case <-listenerCtx.Done():
+ return
+ default:
+ p.listener.(*net.TCPListener).SetDeadline(time.Now().Add(1 * time.Second))
+ conn, err := p.listener.Accept()
+ if err != nil {
+ if ne, ok := err.(net.Error); ok && ne.Timeout() {
+ continue
+ }
+ if strings.Contains(err.Error(), "use of closed network connection") || strings.Contains(err.Error(), "invalid argument") {
+ return
+ }
+ log.Err(err).Str("file", "OS2LPeripheral").Msg("unable to accept the connection")
+ continue
+ }
+
+ // Every client is handled in a dedicated goroutine
+ p.wg.Add(1)
+ go func(c net.Conn) {
+ defer p.wg.Done()
+ defer c.Close()
+
+ buffer := make([]byte, 1024)
+ for {
+ select {
+ case <-listenerCtx.Done():
+ return
+ default:
+ c.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
+ n, err := c.Read(buffer)
+ if err != nil {
+ if ne, ok := err.(net.Error); ok && ne.Timeout() {
+ // Lecture a expiré → vérifier si le contexte est annulé
+ select {
+ case <-listenerCtx.Done():
+ return
+ default:
+ continue // pas annulé → relancer Read
+ }
+ }
+ return // autre erreur ou EOF
+ }
+
+ p.handleMessage(buffer[:n])
+ }
+ }
+ }(conn)
+ }
+ }
+ }()
+ runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), p.GetInfo(), PeripheralStatusActivated)
+
+ log.Info().Str("file", "OS2LPeripheral").Msg("OS2L peripheral activated")
+
+ return nil
+}
+
+// Deactivate deactivates the OS2L peripheral
+func (p *OS2LPeripheral) Deactivate(ctx context.Context) error {
+ if p.listener == nil {
+ return fmt.Errorf("the listener isn't defined")
+ }
+
+ // Cancel listener by context
+ if p.listenerCancel != nil {
+ p.listenerCancel()
+ }
+
+ runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), p.GetInfo(), PeripheralStatusDeactivated)
+
+ log.Info().Str("file", "OS2LPeripheral").Msg("OS2L peripheral deactivated")
+ return nil
+}
+
+// SetSettings sets a specific setting for this peripheral
+func (p *OS2LPeripheral) SetSettings(ctx context.Context, settings map[string]any) error {
+ err := p.loadSettings(settings)
+ if err != nil {
+ return fmt.Errorf("unable to load settings: %w", err)
+ }
+ // Reconnect the peripheral
+ p.wg.Add(1)
+ go func() {
+ defer p.wg.Done()
+ err := p.Deactivate(ctx)
+ if err != nil {
+ log.Err(err).Str("sn", p.GetInfo().SerialNumber).Msg("unable to deactivate")
+ return
+ }
+ err = p.Disconnect(ctx)
+ if err != nil {
+ log.Err(err).Str("sn", p.GetInfo().SerialNumber).Msg("unable to disconnect")
+ return
+ }
+ // Add a sleep to view changes
+ time.Sleep(500 * time.Millisecond)
+ err = p.Connect(ctx)
+ if err != nil {
+ log.Err(err).Str("sn", p.GetInfo().SerialNumber).Msg("unable to connect")
+ return
+ }
+ err = p.Activate(ctx)
+ if err != nil {
+ log.Err(err).Str("sn", p.GetInfo().SerialNumber).Msg("unable to activate")
+ return
+ }
+ }()
+ log.Info().Str("sn", p.GetInfo().SerialNumber).Msg("peripheral settings set")
return nil
}
@@ -91,8 +265,8 @@ func (p *OS2LPeripheral) SetDeviceProperty(context.Context, uint32, uint32, byte
}
// GetSettings gets the peripheral settings
-func (p *OS2LPeripheral) GetSettings() map[string]interface{} {
- return map[string]interface{}{
+func (p *OS2LPeripheral) GetSettings() map[string]any {
+ return map[string]any{
"os2lIp": p.serverIP,
"os2lPort": p.serverPort,
}
@@ -102,3 +276,11 @@ func (p *OS2LPeripheral) GetSettings() map[string]interface{} {
func (p *OS2LPeripheral) GetInfo() PeripheralInfo {
return p.info
}
+
+// WaitStop stops the peripheral
+func (p *OS2LPeripheral) WaitStop() error {
+ log.Info().Str("file", "OS2LPeripheral").Str("s/n", p.info.SerialNumber).Msg("waiting for OS2L peripheral to close...")
+ p.wg.Wait()
+ log.Info().Str("file", "OS2LPeripheral").Str("s/n", p.info.SerialNumber).Msg("OS2L peripheral closed!")
+ return nil
+}
diff --git a/hardware/hardware.go b/hardware/hardware.go
index 466f4b4..81ba457 100644
--- a/hardware/hardware.go
+++ b/hardware/hardware.go
@@ -21,8 +21,10 @@ const (
PeripheralArrival PeripheralEvent = "PERIPHERAL_ARRIVAL"
// PeripheralRemoval is triggered when a peripheral has been disconnected from the system
PeripheralRemoval PeripheralEvent = "PERIPHERAL_REMOVAL"
- // PeripheralStatusUpdated is triggered when a peripheral status has been updated (disconnected - connecting - connected)
+ // PeripheralStatusUpdated is triggered when a peripheral status has been updated (disconnected - connecting - deactivated - activated)
PeripheralStatusUpdated PeripheralEvent = "PERIPHERAL_STATUS"
+ // PeripheralEventEmitted is triggered when a peripheral event is emitted
+ PeripheralEventEmitted PeripheralEvent = "PERIPHERAL_EVENT_EMITTED"
// PeripheralStatusDisconnected : peripheral is now disconnected
PeripheralStatusDisconnected PeripheralStatus = "PERIPHERAL_DISCONNECTED"
// PeripheralStatusConnecting : peripheral is now connecting
diff --git a/hardware/interfaces.go b/hardware/interfaces.go
index d48b3fe..6c9ea82 100644
--- a/hardware/interfaces.go
+++ b/hardware/interfaces.go
@@ -5,39 +5,37 @@ import "context"
// Peripheral represents the methods used to manage a peripheral (input or output hardware)
type Peripheral interface {
Connect(context.Context) error // Connect the peripheral
- IsConnected() bool // Return if the peripheral is connected or not
- Disconnect() error // Disconnect 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
- SetSettings(map[string]interface{}) error // Set a peripheral setting
+ SetSettings(context.Context, map[string]any) error // Set a peripheral setting
SetDeviceProperty(context.Context, uint32, byte) error // Update a device property
+ WaitStop() error // Properly close the peripheral
- GetInfo() PeripheralInfo // Get the peripheral information
- GetSettings() map[string]interface{} // Get the peripheral settings
+ GetInfo() PeripheralInfo // Get the peripheral information
+ GetSettings() map[string]any // Get the peripheral settings
}
// PeripheralInfo represents a peripheral information
type PeripheralInfo struct {
- Name string `yaml:"name"` // Name of the peripheral
- SerialNumber string `yaml:"sn"` // S/N of the peripheral
- ProtocolName string `yaml:"protocol"` // Protocol name of the peripheral
- // IsConnected bool // If the peripheral is connected to the system
- // IsActivated bool // If the peripheral is activated in the project
- // IsDetected bool // If the peripheral is detected by the system
- Settings map[string]interface{} `yaml:"settings"` // Peripheral settings
+ Name string `yaml:"name"` // Name of the peripheral
+ SerialNumber string `yaml:"sn"` // S/N of the peripheral
+ ProtocolName string `yaml:"protocol"` // Protocol name of the peripheral
+ Settings map[string]any `yaml:"settings"` // Peripheral settings
}
// 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]interface{}, error) // Gets the peripheral settings
- SetPeripheralSettings(string, map[string]interface{}) error // Sets the peripheral settings
- GetName() string // Get the name of the finder
+ 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
}
diff --git a/peripherals.go b/peripherals.go
index 91ae570..f9fb409 100644
--- a/peripherals.go
+++ b/peripherals.go
@@ -18,9 +18,10 @@ func (a *App) AddPeripheral(peripheralData hardware.PeripheralInfo) (string, err
// Register this new peripheral
serialNumber, err := f.RegisterPeripheral(a.ctx, peripheralData)
if err != nil {
- log.Trace().Str("file", "peripheral").Str("protocolName", peripheralData.ProtocolName).Str("periphID", serialNumber).Msg("device registered to the finder")
- return "", fmt.Errorf("unable to register the peripheral '%s'", serialNumber)
+ return "", fmt.Errorf("unable to register the peripheral '%s': %w", serialNumber, err)
}
+ log.Trace().Str("file", "peripheral").Str("protocolName", peripheralData.ProtocolName).Str("periphID", serialNumber).Msg("device registered to the finder")
+
// Rewrite the serialnumber for virtual devices
peripheralData.SerialNumber = serialNumber
@@ -35,7 +36,7 @@ func (a *App) AddPeripheral(peripheralData hardware.PeripheralInfo) (string, err
}
// GetPeripheralSettings gets the peripheral settings
-func (a *App) GetPeripheralSettings(protocolName, peripheralID string) (map[string]interface{}, error) {
+func (a *App) GetPeripheralSettings(protocolName, peripheralID string) (map[string]any, error) {
// Get the peripheral from its finder
f, err := a.hardwareManager.GetFinder(protocolName)
if err != nil {
@@ -46,7 +47,7 @@ func (a *App) GetPeripheralSettings(protocolName, peripheralID string) (map[stri
}
// UpdatePeripheralSettings updates a specific setting of a peripheral
-func (a *App) UpdatePeripheralSettings(protocolName, peripheralID string, settings map[string]interface{}) error {
+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 {
@@ -61,7 +62,7 @@ func (a *App) UpdatePeripheralSettings(protocolName, peripheralID string, settin
pInfo.Settings = settings
a.projectInfo.PeripheralsInfo[peripheralID] = pInfo
// Apply changes in the peripheral
- return f.SetPeripheralSettings(peripheralID, pInfo.Settings)
+ return f.SetPeripheralSettings(a.ctx, peripheralID, pInfo.Settings)
}
// RemovePeripheral removes a peripheral from the project
diff --git a/project.go b/project.go
index af7a157..9b9954d 100644
--- a/project.go
+++ b/project.go
@@ -136,7 +136,7 @@ func (a *App) OpenProject(projectInfo ProjectInfo) error {
}
_, err = hostFinder.RegisterPeripheral(a.ctx, value)
if err != nil {
- return fmt.Errorf("unable to register the peripheral S/N '%s'", key)
+ return fmt.Errorf("unable to register the peripheral S/N '%s': %w", key, err)
}
}
return nil