package main import ( "context" "encoding/base64" "time" "github.com/urfave/cli/v3" "git.maze.io/go/ham/protocol/aprs/aprsis" "git.maze.io/go/ham/radio" "git.maze.io/ham/hamview" "git.maze.io/ham/hamview/cmd" ) type aprsisConfig struct { Broker hamview.BrokerConfig `yaml:"broker"` Receiver hamview.APRSISConfig `yaml:"receiver"` Radio map[string]*radio.Info `yaml:"radio"` Include []string `yaml:"include"` } func (config *aprsisConfig) Includes() []string { includes := config.Include config.Include = nil return includes } func runAPRSIS(ctx context.Context, command *cli.Command) error { var config = aprsisConfig{ Receiver: hamview.APRSISConfig{ Listen: hamview.DefaultAPRSISListen, Server: hamview.DefaultAPRSISServer, }, } if err := cmd.Load(logger, command.String(cmd.FlagConfig), &config); err != nil { return err } logger.Infof("receiver: starting APRS-IS proxy on tcp://%s to tcp://%s", config.Receiver.Listen, config.Receiver.Server) proxy, err := aprsis.NewProxy(config.Receiver.Listen, config.Receiver.Server) if err != nil { return err } proxy.OnClient = func(callsign string, client *aprsis.ProxyClient) { go receiveAPRSIS(&config.Broker, callsign, client, config.Radio[callsign]) } return waitForInterrupt() } func receiveAPRSIS(config *hamview.BrokerConfig, callsign string, client *aprsis.ProxyClient, extra *radio.Info) { defer func() { _ = client.Close() }() if extra == nil { logger.Warnf("receiver: no radio info configured for %s!", callsign) } broker, err := hamview.NewBroker(config) if err != nil { logger.Errorf("receiver: can't setup to broker: %v", err) return } defer func() { _ = broker.Close() }() info := client.Info() if extra != nil { info.Manufacturer = pick(info.Manufacturer, extra.Manufacturer) info.Device = pick(info.Device, extra.Device) info.FirmwareDate = pickTime(info.FirmwareDate, extra.FirmwareDate) info.FirmwareVersion = pick(info.FirmwareVersion, extra.FirmwareVersion) info.Antenna = pick(info.Antenna, extra.Antenna) info.Modulation = pick(info.Modulation, extra.Modulation) info.Position = pickPosition(info.Position, extra.Position) info.Frequency = pickFloat64(info.Frequency, extra.Frequency) info.Bandwidth = pickFloat64(info.Bandwidth, extra.Bandwidth) info.Power = pickFloat64(info.Power, extra.Power) info.Gain = pickFloat64(info.Gain, extra.Gain) info.LoRaSF = pickUint8(info.LoRaSF, extra.LoRaSF) info.LoRaCR = pickUint8(info.LoRaCR, extra.LoRaCR) } if err = broker.StartRadio("aprs", info); err != nil { logger.Fatalf("receiver: can't start broker: %v", err) return } id := base64.RawURLEncoding.EncodeToString([]byte(callsign)) logger.Infof("receiver: start receiving packets from station: %s", callsign) for packet := range client.RawPackets() { logger.Debugf("aprs packet: %#+v", packet) if err := broker.PublishPacket("aprs/packet/"+id, packet); err != nil { logger.Error(err) } } logger.Infof("receiver: stopped receiving packets from station: %s", callsign) } func pick(ss ...string) string { for _, s := range ss { if s != "" { return s } } return "" } func pickFloat64(vv ...float64) float64 { for _, v := range vv { if v != 0 { return v } } return 0 } func pickPosition(vv ...*radio.Position) *radio.Position { for _, v := range vv { if v != nil { return v } } return nil } func pickTime(tt ...time.Time) time.Time { for _, t := range tt { if !t.Equal(time.Time{}) { return t } } return time.Time{} } func pickUint8(vv ...uint8) uint8 { for _, v := range vv { if v != 0 { return v } } return 0 }