Skip to content

Commit

Permalink
Support defining hamlib_rigs through env variables
Browse files Browse the repository at this point in the history
The envconfig package introduced in 77cc83b does not handle map of
structs, so we have to handle hamlib_rigs manually.

This also defaults the "network" attribute to "tcp", which is what most
users want (for rigctld).
  • Loading branch information
martinhpedersen committed Nov 7, 2023
1 parent 8e4aa1b commit 2e61f66
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 1 deletion.
2 changes: 1 addition & 1 deletion cfg/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ type Config struct {
}

type HamlibConfig struct {
// The network type ("serial" or "tcp"). Use 'tcp' for rigctld.
// The network type ("serial" or "tcp"). Use 'tcp' for rigctld (default).
//
// (For serial support: build with "-tags libhamlib".)
Network string `json:"network,omitempty"`
Expand Down
41 changes: 41 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package main

import (
"encoding/json"
"fmt"
"log"
"os"
"path"
Expand Down Expand Up @@ -33,6 +34,10 @@ func LoadConfig(cfgPath string, fallback cfg.Config) (config cfg.Config, err err
if err := envconfig.Process(buildinfo.AppName, &config); err != nil {
return config, err
}
// Environment variables for hamlib rigs (custom syntax not handled by envconfig)
if err := readRigsFromEnv(&config.HamlibRigs); err != nil {
return config, err
}

// Ensure the alias "telnet" exists
if config.ConnectAliases == nil {
Expand Down Expand Up @@ -121,6 +126,42 @@ func LoadConfig(cfgPath string, fallback cfg.Config) (config cfg.Config, err err
return config, nil
}

// readRigsFromEnv reads hamlib rigs config from environment.
// Syntax: PAT_HAMLIB_RIGS_{rig name}_{ATTRIBUTE}
// _{ATTRIBUTE} is optional (defaults to _ADDRESS).
// Examples:
// - PAT_HAMLIB_RIGS_rig1_NETWORK=tcp
// - PAT_HAMLIB_RIGS_rig1_ADDRESS=localhost:8080
// - PAT_HAMLIB_RIGS_rig1_VFO=A
// - PAT_HAMLIB_RIGS_rig2=localhost:8080
func readRigsFromEnv(rigs *map[string]cfg.HamlibConfig) error {
prefix := strings.ToUpper(buildinfo.AppName) + "_HAMLIB_RIGS_"
for _, env := range os.Environ() {
attribute, value, _ := strings.Cut(env, "=")
if !strings.HasPrefix(attribute, prefix) {
continue
}
attribute = strings.TrimPrefix(attribute, prefix)
name, attribute, _ := strings.Cut(attribute, "_")
if *rigs == nil {
*rigs = make(map[string]cfg.HamlibConfig)
}
rig := (*rigs)[name]
switch attribute {
case "ADDRESS", "":
rig.Address = value
case "NETWORK":
rig.Network = value
case "VFO":
rig.VFO = value
default:
return fmt.Errorf("invalid attribute '%s' for rig '%s'", attribute, name)
}
(*rigs)[name] = rig
}
return nil
}

func ReadConfig(path string) (config cfg.Config, err error) {
data, err := os.ReadFile(path)
if err != nil {
Expand Down
62 changes: 62 additions & 0 deletions config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package main

import (
"os"
"strings"
"testing"

"github.com/la5nta/pat/cfg"
)

func TestReadRigsFromEnv(t *testing.T) {
const prefix = "PAT_HAMLIB_RIGS"
unset := func() {
for _, env := range os.Environ() {
key, _, _ := strings.Cut(env, "=")
if strings.HasPrefix(key, prefix) {
os.Unsetenv(key)
}
}
}
t.Run("simple", func(t *testing.T) {
defer unset()
var rigs map[string]cfg.HamlibConfig
os.Setenv(prefix+"_rig", "localhost:4532")
if err := readRigsFromEnv(&rigs); err != nil {
t.Fatal(err)
}
if got := rigs["rig"]; (got != cfg.HamlibConfig{Address: "localhost:4532"}) {
t.Fatalf("Got unexpected config: %#v", got)
}
})
t.Run("with VFO", func(t *testing.T) {
defer unset()
var rigs map[string]cfg.HamlibConfig
os.Setenv(prefix+"_rig", "localhost:4532")
os.Setenv(prefix+"_rig_VFO", "A")
if err := readRigsFromEnv(&rigs); err != nil {
t.Fatal(err)
}
if got := rigs["rig"]; (got != cfg.HamlibConfig{Address: "localhost:4532", VFO: "A"}) {
t.Fatalf("Got unexpected config: %#v", got)
}
})
t.Run("full", func(t *testing.T) {
defer unset()
var rigs map[string]cfg.HamlibConfig
os.Setenv(prefix+"_rig_ADDRESS", "/dev/ttyS0")
os.Setenv(prefix+"_rig_NETWORK", "serial")
os.Setenv(prefix+"_rig_VFO", "B")
if err := readRigsFromEnv(&rigs); err != nil {
t.Fatal(err)
}
expect := cfg.HamlibConfig{
Address: "/dev/ttyS0",
Network: "serial",
VFO: "B",
}
if got := rigs["rig"]; got != expect {
t.Fatalf("Got unexpected config: %#v", got)
}
})
}
3 changes: 3 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,9 @@ func loadHamlibRigs() map[string]hamlib.VFO {
log.Printf("Missing address-field for rig '%s', skipping.", name)
continue
}
if conf.Network == "" {
conf.Network = "tcp"
}

rig, err := hamlib.Open(conf.Network, conf.Address)
if err != nil {
Expand Down

0 comments on commit 2e61f66

Please sign in to comment.