From 8804cead91d2a46d6331865846d7d347d67f656a Mon Sep 17 00:00:00 2001 From: Florian Thienel Date: Sun, 10 Dec 2023 14:27:45 +0100 Subject: [PATCH] allow mutliple hamlib connections --- cmd/root.go | 4 +- pkg/hamdeck/connections_test.go | 2 +- pkg/hamdeck/hamdeck.go | 38 +++++++++++-- pkg/hamlib/factory.go | 98 ++++++++++++++++++++++++++++----- 4 files changed, 118 insertions(+), 24 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 2968a21..6382462 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -96,9 +96,7 @@ func run(cmd *cobra.Command, args []string) { deck := hamdeck.New(device) deck.RegisterFactory(hamdeck.NewButtonFactory(deck)) deck.RegisterFactory(pulse.NewButtonFactory()) - if rootFlags.hamlibAddress != "" { - deck.RegisterFactory(hamlib.NewButtonFactory(rootFlags.hamlibAddress)) - } + deck.RegisterFactory(hamlib.NewButtonFactory(deck, rootFlags.hamlibAddress)) if rootFlags.tciAddress != "" { deck.RegisterFactory(tci.NewButtonFactory(rootFlags.tciAddress)) } diff --git a/pkg/hamdeck/connections_test.go b/pkg/hamdeck/connections_test.go index a547144..8b39bb0 100644 --- a/pkg/hamdeck/connections_test.go +++ b/pkg/hamdeck/connections_test.go @@ -68,7 +68,7 @@ func (p *testConnectionProvider) GetConnection(name string, connectionType strin return p.config, true } -func (p *testConnectionProvider) CreateConnection(config ConnectionConfig) (*testConnection, error) { +func (p *testConnectionProvider) CreateConnection(_ string, config ConnectionConfig) (*testConnection, error) { return &testConnection{ config: config, }, nil diff --git a/pkg/hamdeck/hamdeck.go b/pkg/hamdeck/hamdeck.go index 6dd29d3..47b8352 100644 --- a/pkg/hamdeck/hamdeck.go +++ b/pkg/hamdeck/hamdeck.go @@ -313,19 +313,23 @@ func (h *LongpressHandler) Released() { h.timer.Stop() } +const LegacyConnectionName = "" + type ConnectionConfig map[string]any type ConnectionConfigProvider interface { GetConnection(string, string) (ConnectionConfig, bool) } -type ConnectionFactory[T any] func(ConnectionConfig) (T, error) +type ConnectionFactory[T any] func(string, ConnectionConfig) (T, error) type ConnectionManager[T any] struct { - connectionType string - provider ConnectionConfigProvider - factory ConnectionFactory[T] - connections map[string]T + connectionType string + provider ConnectionConfigProvider + factory ConnectionFactory[T] + connections map[string]T + hasLegacy bool + legacyConnection T } func NewConnectionManager[T any](connectionType string, provider ConnectionConfigProvider, factory ConnectionFactory[T]) *ConnectionManager[T] { @@ -337,7 +341,20 @@ func NewConnectionManager[T any](connectionType string, provider ConnectionConfi } } +func (m *ConnectionManager[T]) SetLegacy(legacyConnection T) { + m.hasLegacy = true + m.legacyConnection = legacyConnection +} + func (m *ConnectionManager[T]) Get(name string) (T, error) { + var connection T + if name == LegacyConnectionName { + if !m.hasLegacy { + return connection, fmt.Errorf("no legacy %s connection defined", m.connectionType) + } + return m.legacyConnection, nil + } + connection, ok := m.connections[name] if ok { return connection, nil @@ -348,7 +365,7 @@ func (m *ConnectionManager[T]) Get(name string) (T, error) { return connection, fmt.Errorf("no %s connection defined with name %s", m.connectionType, name) } - connection, err := m.factory(config) + connection, err := m.factory(name, config) if err != nil { return connection, err } @@ -357,3 +374,12 @@ func (m *ConnectionManager[T]) Get(name string) (T, error) { return connection, nil } + +func (m *ConnectionManager[T]) ForEach(f func(T)) { + for _, connection := range m.connections { + f(connection) + } + if m.hasLegacy { + f(m.legacyConnection) + } +} diff --git a/pkg/hamlib/factory.go b/pkg/hamlib/factory.go index 3ecfc52..fe86cc2 100644 --- a/pkg/hamlib/factory.go +++ b/pkg/hamlib/factory.go @@ -1,6 +1,7 @@ package hamlib import ( + "fmt" "log" "github.com/ftl/rigproxy/pkg/client" @@ -9,6 +10,7 @@ import ( ) const ( + ConfigAddress = "address" ConfigCommand = "command" ConfigArgs = "args" ConfigMode = "mode" @@ -24,6 +26,7 @@ const ( ) const ( + ConnectionType = "hamlib" SetModeButtonType = "hamlib.SetMode" ToggleModeButtonType = "hamlib.ToggleMode" SetButtonType = "hamlib.Set" @@ -33,21 +36,39 @@ const ( SetVFOButtonType = "hamlib.SetVFO" ) -func NewButtonFactory(address string) *Factory { - client := NewClient(address) - client.KeepOpen() +func NewButtonFactory(provider hamdeck.ConnectionConfigProvider, legacyAddress string) *Factory { + result := &Factory{} + result.connections = hamdeck.NewConnectionManager(ConnectionType, provider, result.createHamlibClient) - return &Factory{ - client: client, + if legacyAddress != "" { + client := NewClient(legacyAddress) + client.KeepOpen() + result.connections.SetLegacy(client) } + + return result } type Factory struct { - client *HamlibClient + connections *hamdeck.ConnectionManager[*HamlibClient] +} + +func (f *Factory) createHamlibClient(name string, config hamdeck.ConnectionConfig) (*HamlibClient, error) { + address, ok := hamdeck.ToString(config[ConfigAddress]) + if !ok { + return nil, fmt.Errorf("no address defined for hamlib connection %s", name) + } + + client := NewClient(address) + client.KeepOpen() + + return client, nil } func (f *Factory) Close() { - f.client.Close() + f.connections.ForEach(func(client *HamlibClient) { + client.Close() + }) } func (f *Factory) CreateButton(config map[string]interface{}) hamdeck.Button { @@ -79,7 +100,14 @@ func (f *Factory) createSetModeButton(config map[string]interface{}) hamdeck.But return nil } - return NewSetModeButton(f.client, client.Mode(mode), label) + connection, _ := hamdeck.ToString(config[hamdeck.ConfigConnection]) + hamlibClient, err := f.connections.Get(connection) + if err != nil { + log.Printf("Cannot create hamlib.SetMode button: %v", err) + return nil + } + + return NewSetModeButton(hamlibClient, client.Mode(mode), label) } func (f *Factory) createToggleModeButton(config map[string]interface{}) hamdeck.Button { @@ -92,7 +120,14 @@ func (f *Factory) createToggleModeButton(config map[string]interface{}) hamdeck. return nil } - return NewToggleModeButton(f.client, client.Mode(mode1), label1, client.Mode(mode2), label2) + connection, _ := hamdeck.ToString(config[hamdeck.ConfigConnection]) + hamlibClient, err := f.connections.Get(connection) + if err != nil { + log.Printf("Cannot create hamlib.ToggleMode button: %v", err) + return nil + } + + return NewToggleModeButton(hamlibClient, client.Mode(mode1), label1, client.Mode(mode2), label2) } func (f *Factory) createSetButton(config map[string]interface{}) hamdeck.Button { @@ -104,7 +139,14 @@ func (f *Factory) createSetButton(config map[string]interface{}) hamdeck.Button return nil } - return NewSetButton(f.client, label, command, args...) + connection, _ := hamdeck.ToString(config[hamdeck.ConfigConnection]) + hamlibClient, err := f.connections.Get(connection) + if err != nil { + log.Printf("Cannot create hamlib.Set button: %v", err) + return nil + } + + return NewSetButton(hamlibClient, label, command, args...) } func (f *Factory) createSwitchToBandButton(config map[string]interface{}) hamdeck.Button { @@ -116,7 +158,14 @@ func (f *Factory) createSwitchToBandButton(config map[string]interface{}) hamdec return nil } - return NewSwitchToBandButton(f.client, label, band, useUpDown) + connection, _ := hamdeck.ToString(config[hamdeck.ConfigConnection]) + hamlibClient, err := f.connections.Get(connection) + if err != nil { + log.Printf("Cannot create hamlib.SwitchToBand button: %v", err) + return nil + } + + return NewSwitchToBandButton(hamlibClient, label, band, useUpDown) } func (f *Factory) createSetPowerLevelButton(config map[string]interface{}) hamdeck.Button { @@ -127,13 +176,27 @@ func (f *Factory) createSetPowerLevelButton(config map[string]interface{}) hamde return nil } - return NewSetPowerLevelButton(f.client, label, value) + connection, _ := hamdeck.ToString(config[hamdeck.ConfigConnection]) + hamlibClient, err := f.connections.Get(connection) + if err != nil { + log.Printf("Cannot create hamlib.SetPowerLevel button: %v", err) + return nil + } + + return NewSetPowerLevelButton(hamlibClient, label, value) } func (f *Factory) createMOXButton(config map[string]interface{}) hamdeck.Button { label, _ := hamdeck.ToString(config[ConfigLabel]) - return NewMOXButton(f.client, label) + connection, _ := hamdeck.ToString(config[hamdeck.ConfigConnection]) + hamlibClient, err := f.connections.Get(connection) + if err != nil { + log.Printf("Cannot create hamlib.MOX button: %v", err) + return nil + } + + return NewMOXButton(hamlibClient, label) } func (f *Factory) createSetVFOButton(config map[string]interface{}) hamdeck.Button { @@ -144,5 +207,12 @@ func (f *Factory) createSetVFOButton(config map[string]interface{}) hamdeck.Butt return nil } - return NewSetVFOButton(f.client, label, client.VFO(vfo)) + connection, _ := hamdeck.ToString(config[hamdeck.ConfigConnection]) + hamlibClient, err := f.connections.Get(connection) + if err != nil { + log.Printf("Cannot create hamlib.SetVFO button: %v", err) + return nil + } + + return NewSetVFOButton(hamlibClient, label, client.VFO(vfo)) }