diff --git a/app.go b/app.go index 36d1024..f55e03f 100644 --- a/app.go +++ b/app.go @@ -28,9 +28,9 @@ type App struct { func NewApp() *App { // Create a new hadware manager hardwareManager := hardware.NewHardwareManager() - hardwareManager.RegisterFinder(hardware.NewMIDIFinder(5 * time.Second)) + // hardwareManager.RegisterFinder(hardware.NewMIDIFinder(5 * time.Second)) hardwareManager.RegisterFinder(hardware.NewFTDIFinder(5 * time.Second)) - hardwareManager.RegisterFinder(hardware.NewOS2LFinder()) + // hardwareManager.RegisterFinder(hardware.NewOS2LFinder()) return &App{ hardwareManager: hardwareManager, projectSave: "", diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index 032ecde..0b54732 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -54,9 +54,24 @@ generateToast('warning', 'bxs-hdd', $_("peripheralRemovalToast") + ' ' + peripheralInfo.Name + '') }) + // Handle the event when a peripheral status is updated + EventsOn('PERIPHERAL_STATUS', function(peripheral, status){ + console.log("Hardware status has been updated to " + status); + // When a peripheral status is updated, update it in the store + peripherals.update((storedPeripherals) => { + return { + ...storedPeripherals, + [peripheral.SerialNumber]: { + ...storedPeripherals[peripheral.SerialNumber], + isSaved: true, + Status: status, + }, + }}) + }) + // Set the window title $: { - WindowSetTitle("DMXConnect - " + $showInformation.Name + ($needProjectSave ? " (unsaved)" : "")) + WindowSetTitle("DMXConnect - " + $showInformation.Name + ($needProjectSave ? " (" + $_("unsavedProjectFlag") + ")" : "")) } let selectedMenu = "settings" diff --git a/frontend/src/components/Settings/DeviceCard.svelte b/frontend/src/components/Settings/DeviceCard.svelte index 6a85854..0c0a46e 100644 --- a/frontend/src/components/Settings/DeviceCard.svelte +++ b/frontend/src/components/Settings/DeviceCard.svelte @@ -14,9 +14,8 @@ export let addable = false; export let signalizable = false; export let signalized = false; - export let disconnected = false; export let selected = false; - export let waiting = false; + export let status = "disconnected"; // Emit a delete event when the device is being removed const dispatch = createEventDispatcher(); @@ -38,11 +37,11 @@
-
+
-

{#if disconnected} {/if}{title}

+

{#if status == "disconnected" } {/if}{title}

{type} {location != '' ? "- " : ""}{location}
- {#if disconnected} + {#if status == "disconnected"}
Disconnected
{:else}
{line1}
@@ -51,9 +50,9 @@
- - - + + +
diff --git a/frontend/src/components/Settings/InputsOutputsContent.svelte b/frontend/src/components/Settings/InputsOutputsContent.svelte index 02341a8..5b4d796 100644 --- a/frontend/src/components/Settings/InputsOutputsContent.svelte +++ b/frontend/src/components/Settings/InputsOutputsContent.svelte @@ -12,15 +12,17 @@ function addPeripheral(peripheral){ // Add the peripheral to the project (backend) AddPeripheral(peripheral).then((serialNumber) => { - peripheral.SerialNumber = serialNumber - peripherals.update((value) => { - // If the peripheral doesn't exists yet, create it - if (!(peripheral.SerialNumber in value)) { - value[peripheral.SerialNumber] = peripheral - } - value[peripheral.SerialNumber].isSaved = true; - return {...value} - }) + peripherals.update((storedPeripherals) => { + return { + ...storedPeripherals, + [serialNumber]: { + ...storedPeripherals[serialNumber], + Name: peripheral.Name, + ProtocolName: peripheral.ProtocolName, + SerialNumber: serialNumber, + isSaved: true, + }, + }}) $needProjectSave = true }).catch((error) => { console.log("Unable to add the peripheral to the project: " + error) @@ -62,15 +64,15 @@ let selectedPeripheralSettings = {} function selectPeripheral(peripheral){ // Load the settings array if the peripheral is detected - if (peripheral.isDetected){ + if (peripheral.isSaved){ GetPeripheralSettings(peripheral.ProtocolName, peripheral.SerialNumber).then((peripheralSettings) => { selectedPeripheralSettings = peripheralSettings + // Select the current peripheral + selectedPeripheralSN = peripheral.SerialNumber }).catch((error) => { console.log("Unable to get the peripheral settings: " + error) generateToast('danger', 'bx-error', $_("getPeripheralSettingsErrorToast")) }) - // Select the current peripheral - selectedPeripheralSN = peripheral.SerialNumber } } @@ -97,7 +99,6 @@ boolean: Boolean, }[typeof(selectedPeripheralSettings[settingName])] || (x => x) selectedPeripheralSettings[settingName] = convert(settingValue) - console.log(typeof(selectedPeripheralSettings[settingName])) let peripheralProtocolName = get(peripherals)[selectedPeripheralSN].ProtocolName UpdatePeripheralSettings(peripheralProtocolName, selectedPeripheralSN, selectedPeripheralSettings).then(()=> { $needProjectSave = true @@ -119,7 +120,7 @@ if(!peripheral.isSaved) addPeripheral(peripheral) }} - title={peripheral.Name} type={peripheral.ProtocolName} location={peripheral.Location ? peripheral.Location : ""} line1={"S/N: " + peripheral.SerialNumber} addable={!peripheral.isSaved}/> + status="connected" title={peripheral.Name} type={peripheral.ProtocolName} location={peripheral.Location ? peripheral.Location : ""} line1={"S/N: " + peripheral.SerialNumber} addable={!peripheral.isSaved}/> {/if} {/each}

{$_("projectHardwareOthersLabel")}

@@ -133,8 +134,8 @@ {#if savedPeripheralNumber > 0} {#each Object.entries($peripherals) as [serialNumber, peripheral]} {#if peripheral.isSaved} - removePeripheral(peripheral)} on:dblclick={() => removePeripheral(peripheral)} on:click={() => selectPeripheral(peripheral)} - disconnected={!peripheral.isDetected} title={peripheral.Name} type={peripheral.ProtocolName} location={peripheral.Location ? peripheral.Location : ""} line1={peripheral.SerialNumber ? "S/N: " + peripheral.SerialNumber : ""} selected={serialNumber == selectedPeripheralSN} removable signalizable/> + 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/> {/if} {/each} {:else} diff --git a/frontend/src/lang/en.json b/frontend/src/lang/en.json index 7e7de71..51e7be1 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", + "unsavedProjectFlag": "unsaved", "projectPropertiesTab": "Project properties", "projectPropertiesTooltip": "The project properties", "projectInputOutputTab": "Hardware", diff --git a/hardware/FTDIFinder.go b/hardware/FTDIFinder.go index 075fa92..e7a489c 100644 --- a/hardware/FTDIFinder.go +++ b/hardware/FTDIFinder.go @@ -15,6 +15,7 @@ import ( "time" "github.com/rs/zerolog/log" + "github.com/wailsapp/wails/v2/pkg/runtime" ) const ( @@ -54,10 +55,10 @@ func (f *FTDIFinder) RegisterPeripheral(ctx context.Context, peripheralData Peri } // UnregisterPeripheral unregisters an existing peripheral -func (f *FTDIFinder) UnregisterPeripheral(ctx context.Context, peripheralID string) error { +func (f *FTDIFinder) UnregisterPeripheral(peripheralID string) error { peripheral, registered := f.registeredPeripherals[peripheralID] if registered { - err := peripheral.Disconnect(ctx) + err := peripheral.Disconnect() if err != nil { return err } @@ -248,13 +249,22 @@ func (f *FTDIFinder) scanPeripherals(ctx context.Context) error { ProtocolName: "FTDI", } - // If this peripheral is already registered, connect it + // If this peripheral is already registered, connect it and activate it peripheral, registered := f.registeredPeripherals[peripheralInfo[1]] if registered { + runtime.EventsEmit(ctx, string(PeripheralStatus), peripheral.info, "connecting") + time.Sleep(2 * time.Second) err := peripheral.Connect(ctx, location) if err != nil { log.Err(err).Str("file", "FTDIFinder").Str("peripheralSN", peripheralInfo[1]).Msg("unable to connect the peripheral") } + runtime.EventsEmit(ctx, string(PeripheralStatus), peripheral.info, "deactivated") + time.Sleep(2 * time.Second) + err = peripheral.Activate(ctx) + if err != nil { + log.Err(err).Str("file", "FTDIFinder").Str("peripheralSN", peripheralInfo[1]).Msg("unable to activate the peripheral") + } + runtime.EventsEmit(ctx, string(PeripheralStatus), peripheral.info, "activated") } log.Trace().Any("periph", temporaryPeripherals).Str("file", "FTDIFinder").Str("peripheralName", peripheralInfo[2]).Msg("successfully added the FTDI peripheral to the finder") diff --git a/hardware/FTDIPeripheral.go b/hardware/FTDIPeripheral.go index 7e03e57..7d218d8 100644 --- a/hardware/FTDIPeripheral.go +++ b/hardware/FTDIPeripheral.go @@ -6,6 +6,7 @@ import ( _ "embed" "fmt" "io" + "path/filepath" "github.com/rs/zerolog/log" @@ -37,6 +38,7 @@ func NewFTDIPeripheral(info PeripheralInfo) (*FTDIPeripheral, error) { log.Info().Str("file", "FTDIPeripheral").Str("name", info.Name).Str("s/n", info.SerialNumber).Msg("FTDI peripheral created") settings := make(map[string]interface{}) return &FTDIPeripheral{ + programName: filepath.Join(os.TempDir(), ftdiSenderExecutableName), info: info, dmxSender: nil, settings: settings, @@ -94,6 +96,10 @@ func (p *FTDIPeripheral) Connect(ctx context.Context, location int) error { select { case <-ctx.Done(): // If the context is canceled, handle it gracefully + err = p.Disconnect() + if err != nil { + log.Err(err).Str("file", "FTDIPeripheral").Msg("unable to disconnect the peripheral") + } log.Warn().Str("file", "FTDIPeripheral").Str("s/n", p.info.SerialNumber).Msg("dmxSender was canceled by context") return default: @@ -114,7 +120,7 @@ func (p *FTDIPeripheral) Connect(ctx context.Context, location int) error { } // Disconnect disconnects the FTDI peripheral -func (p *FTDIPeripheral) Disconnect(ctx context.Context) error { +func (p *FTDIPeripheral) Disconnect() error { log.Trace().Str("file", "FTDIPeripheral").Str("s/n", p.info.SerialNumber).Msg("disconnecting FTDI peripheral...") if p.dmxSender != nil { log.Debug().Str("file", "FTDIPeripheral").Str("s/n", p.info.SerialNumber).Msg("dmxsender is defined for this FTDI") @@ -174,10 +180,10 @@ func (p *FTDIPeripheral) SetSettings(settings map[string]interface{}) error { } // SetDeviceProperty sends a command to the specified device -func (p *FTDIPeripheral) SetDeviceProperty(ctx context.Context, uint32, channelNumber uint32, channelValue byte) error { +func (p *FTDIPeripheral) SetDeviceProperty(ctx context.Context, channelNumber uint32, channelValue byte) error { if p.dmxSender != nil { log.Debug().Str("file", "FTDIPeripheral").Str("s/n", p.info.SerialNumber).Msg("dmxsender is defined for this FTDI") - commandString := []byte{0x03, 0x01, 0x00, 0xff, 0x03, 0x02, 0x00, channelValue} + commandString := []byte{0x03, byte(channelNumber & 0xFF), byte((channelNumber >> 8) & 0xFF), channelValue} _, err := io.WriteString(p.stdin, string(commandString)) if err != nil { log.Err(err).Str("file", "FTDIPeripheral").Str("s/n", p.info.SerialNumber).Msg("unable to write command to sender") diff --git a/hardware/MIDIFinder.go b/hardware/MIDIFinder.go index ecc4100..4feb2d8 100644 --- a/hardware/MIDIFinder.go +++ b/hardware/MIDIFinder.go @@ -48,10 +48,10 @@ func (f *MIDIFinder) RegisterPeripheral(ctx context.Context, peripheralData Peri } // UnregisterPeripheral unregisters an existing peripheral -func (f *MIDIFinder) UnregisterPeripheral(ctx context.Context, peripheralID string) error { +func (f *MIDIFinder) UnregisterPeripheral(peripheralID string) error { peripheral, registered := f.registeredPeripherals[peripheralID] if registered { - err := peripheral.Disconnect(ctx) + err := peripheral.Disconnect() if err != nil { return err } diff --git a/hardware/MIDIPeripheral.go b/hardware/MIDIPeripheral.go index a143b64..16aadef 100644 --- a/hardware/MIDIPeripheral.go +++ b/hardware/MIDIPeripheral.go @@ -28,7 +28,7 @@ func (p *MIDIPeripheral) Connect(ctx context.Context) error { } // Disconnect disconnects the MIDI peripheral -func (p *MIDIPeripheral) Disconnect(ctx context.Context) error { +func (p *MIDIPeripheral) Disconnect() error { return nil } diff --git a/hardware/OS2LFinder.go b/hardware/OS2LFinder.go index 2acdb8e..24a8d42 100644 --- a/hardware/OS2LFinder.go +++ b/hardware/OS2LFinder.go @@ -38,26 +38,27 @@ func (f *OS2LFinder) RegisterPeripheral(ctx context.Context, peripheralData Peri 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 + } f.registeredPeripherals[peripheralData.SerialNumber] = *os2lPeripheral log.Trace().Any("periph", &os2lPeripheral).Str("file", "OS2LFinder").Str("peripheralName", peripheralData.Name).Msg("OS2L peripheral has been created") - // Send the change to the front - // runtime.EventsEmit(ctx, string(PeripheralArrival), peripheralData) return peripheralData.SerialNumber, nil } // UnregisterPeripheral unregisters an existing peripheral -func (f *OS2LFinder) UnregisterPeripheral(ctx context.Context, peripheralID string) error { +func (f *OS2LFinder) UnregisterPeripheral(peripheralID string) error { peripheral, registered := f.registeredPeripherals[peripheralID] if registered { - err := peripheral.Disconnect(ctx) + err := peripheral.Disconnect() if err != nil { return err } } delete(f.registeredPeripherals, peripheralID) - // Send the change to the front - // runtime.EventsEmit(ctx, string(PeripheralRemoval), peripheral.GetInfo()) return nil } @@ -71,10 +72,10 @@ func (f *OS2LFinder) GetPeripheralSettings(peripheralID string) (map[string]inte // Return the specified peripheral peripheral, found := f.registeredPeripherals[peripheralID] if !found { - log.Error().Str("file", "OS2LFinder").Str("peripheralID", peripheralID).Msg("unable to get this peripheral from the FTDI finder") + 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") } - log.Debug().Str("file", "OS2LFinder").Str("peripheralID", peripheralID).Msg("peripheral found by the FTDI finder") + log.Debug().Str("file", "OS2LFinder").Str("peripheralID", peripheralID).Msg("peripheral found by the OS2L finder") return peripheral.GetSettings(), nil } diff --git a/hardware/OS2LPeripheral.go b/hardware/OS2LPeripheral.go index 6e12008..07e69a0 100644 --- a/hardware/OS2LPeripheral.go +++ b/hardware/OS2LPeripheral.go @@ -3,8 +3,10 @@ package hardware import ( "context" "fmt" + "time" "github.com/rs/zerolog/log" + "github.com/wailsapp/wails/v2/pkg/runtime" ) // OS2LPeripheral contains the data of an OS2L peripheral @@ -27,11 +29,16 @@ func NewOS2LPeripheral(peripheralData PeripheralInfo) (*OS2LPeripheral, error) { // Connect connects the MIDI peripheral func (p *OS2LPeripheral) Connect(ctx context.Context) error { log.Info().Str("file", "OS2LPeripheral").Msg("OS2L peripheral connected") + go func() { + runtime.EventsEmit(ctx, string(PeripheralStatus), p.info, "connecting") + time.Sleep(5 * time.Second) + runtime.EventsEmit(ctx, string(PeripheralStatus), p.info, "disconnected") + }() return nil } // Disconnect disconnects the MIDI peripheral -func (p *OS2LPeripheral) Disconnect(ctx context.Context) error { +func (p *OS2LPeripheral) Disconnect() error { log.Info().Str("file", "OS2LPeripheral").Msg("OS2L peripheral disconnected") return nil } diff --git a/hardware/hardware.go b/hardware/hardware.go index 1409567..5fc1af0 100644 --- a/hardware/hardware.go +++ b/hardware/hardware.go @@ -19,6 +19,8 @@ const ( PeripheralArrival PeripheralEvent = "PERIPHERAL_ARRIVAL" // PeripheralRemoval is triggered when a peripheral has been disconnected from the system PeripheralRemoval PeripheralEvent = "PERIPHERAL_REMOVAL" + // PeripheralStatus is triggered when a peripheral status has been updated (disconnected - connecting - connected) + PeripheralStatus PeripheralEvent = "PERIPHERAL_STATUS" // debounceDuration = 500 * time.Millisecond ) diff --git a/hardware/interfaces.go b/hardware/interfaces.go index 2041002..629df01 100644 --- a/hardware/interfaces.go +++ b/hardware/interfaces.go @@ -4,12 +4,12 @@ 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 - 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 - SetDeviceProperty(context.Context, uint32, uint32, byte) error // Update a device property + Connect(context.Context) error // Connect the peripheral + Disconnect() 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 + SetDeviceProperty(context.Context, uint32, byte) error // Update a device property GetInfo() PeripheralInfo // Get the peripheral information GetSettings() map[string]interface{} // Get the peripheral settings @@ -30,7 +30,7 @@ type PeripheralFinder interface { Stop() error // Stop the detection ForceScan() // Explicitly scans for peripherals RegisterPeripheral(context.Context, PeripheralInfo) (string, error) // Registers a new peripheral data - UnregisterPeripheral(context.Context, string) error // Unregisters an existing peripheral + UnregisterPeripheral(string) 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 diff --git a/peripherals.go b/peripherals.go index 9120603..d359f97 100644 --- a/peripherals.go +++ b/peripherals.go @@ -64,7 +64,7 @@ func (a *App) UpdatePeripheralSettings(protocolName, peripheralID string, settin return f.SetPeripheralSettings(peripheralID, pInfo.Settings) } -// RemovePeripheral adds a peripheral to the project +// RemovePeripheral removes a peripheral from the project func (a *App) RemovePeripheral(protocolName string, peripheralID string) error { // Unregister the peripheral from the finder f, err := a.hardwareManager.GetFinder(protocolName) @@ -72,7 +72,7 @@ func (a *App) RemovePeripheral(protocolName string, peripheralID string) error { log.Err(err).Str("file", "peripherals").Str("protocolName", protocolName).Msg("unable to find the finder") return fmt.Errorf("unable to find the finder") } - err = f.UnregisterPeripheral(a.ctx, peripheralID) + err = f.UnregisterPeripheral(peripheralID) if err != nil { log.Err(err).Str("file", "peripherals").Str("peripheralID", peripheralID).Msg("unable to unregister this peripheral") return fmt.Errorf("unable to unregister this peripheral") @@ -85,19 +85,6 @@ func (a *App) RemovePeripheral(protocolName string, peripheralID string) error { // FOR TESTING PURPOSE ONLY -// func (a *App) ConnectFTDI() 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.Connect(a.ctx) -// } - // func (a *App) ActivateFTDI() error { // // Connect the FTDI // driver, err := a.hardwareManager.GetFinder("FTDI") @@ -136,16 +123,3 @@ func (a *App) RemovePeripheral(protocolName string, peripheralID string) error { // } // return periph.Deactivate(a.ctx) // } - -// func (a *App) DisconnectFTDI() 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.Disconnect(a.ctx) -// }