Skip to content

Commit

Permalink
1.0.2
Browse files Browse the repository at this point in the history
* Resolved a bug parsing config-supplied additional subprocess args
* Additional logging of subprocess stderr
* Fixed a hanging subprocess after quit
  • Loading branch information
cceremuga authored Nov 15, 2022
1 parent b88ca6a commit baee180
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 60 deletions.
10 changes: 3 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ This project is the next-generation successor to [PyPacket](https://gihub.com/cc

## Release Notes

* 11/6/2022 ([1.0.2 release](https://github.com/cceremuga/ionosphere/releases/tag/v1.0.2))
* Fixed [an issue](https://github.com/cceremuga/ionosphere/issues/18) with config-supplied args for `rtl_fm` and `multimon-sg`.
* Logging is now more verbose, including error output during the startup sequence for the underlying `rtl_fm`, `multimon-ng` processes.
* 11/4/2022 ([1.0.1 release](https://github.com/cceremuga/ionosphere/releases/tag/v1.0.1))
* Fixed an infinite loop when an unexpected APRS-IS connection drop occurs.
* Fixed panic crashes caused when parsing packet type names.
Expand All @@ -19,13 +22,6 @@ This project is the next-generation successor to [PyPacket](https://gihub.com/cc
* Added APRS-IS digipeat output.
* Documentation updates.
* Fixed numerous small bugs.
* 4/12/2021
* Fixed beacon interval.
* Updated dependencies, removed some.
* 3/9/2021 ([1.0.0-beta1 release](https://github.com/cceremuga/ionosphere/releases/tag/v1.0.0-beta1))
* Receives, decodes, logs APRS packets to terminal, warnings and errors to file.
* Uploads APRS packets, periodic beacons to APRS-IS.
* Allows for full configuration RTL-SDR, multimon-ng options via simple YAML.

## Requirements

Expand Down
2 changes: 1 addition & 1 deletion handlers/aprsis/aprsis.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (s APRSIS) Enabled() bool {
}

if !enabled {
log.Println("APRS-IS handler inactive.")
log.Debug("APRS-IS handler inactive.")
}

return enabled
Expand Down
38 changes: 32 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
package main

import (
"fmt"
"io"
"os"
"os/signal"
"syscall"

"github.com/cceremuga/ionosphere/services/config"
"github.com/cceremuga/ionosphere/services/handler"
"github.com/cceremuga/ionosphere/services/log"
"github.com/cceremuga/ionosphere/services/packet"
"github.com/cceremuga/ionosphere/subprocesses/multimon"
"github.com/cceremuga/ionosphere/subprocesses/rtlsdr"
"github.com/cceremuga/ionosphere/subprocesses/rtlfm"
"github.com/cceremuga/ionosphere/tasks/beacon"
"github.com/fatih/color"
)
Expand All @@ -27,9 +31,12 @@ const logo = `

func main() {
color.Cyan(logo)
log.Debug("Ionosphere initializing.")

c := config.Load()

rtl := rtlsdr.Build(&c.Rtl)
// Pipe io from rtl_fm to multimon-ng
rtl := rtlfm.Build(&c.Rtl)
mult := multimon.Build(&c.Multimon)

r, w := io.Pipe()
Expand All @@ -38,16 +45,35 @@ func main() {

// Start handlers, then subprocesses.
handler.Start()
rtlsdr.Start(rtl)
rtlfm.Start(rtl)
multimon.Start(mult, packet.Decode)
beacon.Start(&c.Beacon)

log.Println("Listening for packets.")

// Listen for exit signals, set up for a clean exit.
sigchan := make(chan os.Signal, 1)
signal.Notify(sigchan,
syscall.SIGINT,
syscall.SIGKILL,
syscall.SIGTERM,
syscall.SIGQUIT)
go func() {
defer w.Close()
s := <-sigchan
log.Debug(fmt.Sprintf("Signal (%s) caught, terminating processes.", s))

w.Close()
rtl.Process.Kill()
mult.Process.Kill()

log.Debug("Ionosphere exiting!")
os.Exit(0)
}()

log.Debug("Listening for packets.")

// Perform a clean exit if one of the subprocesses terms early.
go func() {
rtl.Wait()
w.Close()
}()

mult.Wait()
Expand Down
6 changes: 3 additions & 3 deletions services/aprsis/aprsis.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func Connect(options map[string]string) {
if err != nil {
log.Fatal(err)
} else {
log.Info(fmt.Sprintf("Connected to APRS-IS: %s", config.server))
log.Debug(fmt.Sprintf("Connected to APRS-IS: %s", config.server))
}

// Send auth
Expand Down Expand Up @@ -76,14 +76,14 @@ func Connect(options map[string]string) {
if err != nil {
log.Fatal(err)
} else {
log.Info("Successfully authenticated with APRS-IS.")
log.Debug("Successfully authenticated with APRS-IS.")
}

conn = c
connected = true

go func() {
log.Info("Listening for responses from APRS-IS.")
log.Debug("Listening for responses from APRS-IS.")

for {
message, err := c.ReadLine()
Expand Down
4 changes: 3 additions & 1 deletion services/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
package handler

import (
"fmt"

"github.com/cceremuga/ionosphere/handlers/aprsis"
"github.com/cceremuga/ionosphere/handlers/stdout"
"github.com/cceremuga/ionosphere/interfaces"
Expand All @@ -23,7 +25,7 @@ func Start() []interfaces.Handler {
}

h.Start()
log.Printf("%s handler initialized.", h.Name())
log.Debug(fmt.Sprintf("%s handler initialized.", h.Name()))
cache = append(cache, h)
}

Expand Down
24 changes: 18 additions & 6 deletions services/log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,27 @@ var fileLog *logrus.Logger
func init() {
stdoutLog = logrus.New()
stdoutLog.SetOutput(os.Stdout)
stdoutLog.SetLevel(logrus.DebugLevel)

fileLog = logrus.New()

file, err := os.OpenFile("logs/ionosphere.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
file, err := os.OpenFile(
"logs/ionosphere.log",
os.O_CREATE|os.O_WRONLY|os.O_APPEND,
0666,
)
if err == nil {
fileLog.SetOutput(file)
fileLog.SetLevel(logrus.WarnLevel)
fileLog.SetLevel(logrus.DebugLevel)
} else {
stdoutLog.Fatal("Failed to initialize log file.")
}
}

// Println wraps logger.Println
func Println(args ...interface{}) {
stdoutLog.Println(args...)
fileLog.Println(args...)
// Debug wraps logger.Debug
func Debug(args ...interface{}) {
stdoutLog.Debug(args...)
fileLog.Debug(args...)
}

// Info wraps logger.Info
Expand Down Expand Up @@ -66,3 +71,10 @@ func Printf(msg string, args ...interface{}) {
stdoutLog.Printf(msg, args...)
fileLog.Printf(msg, args...)
}

type StderrLogger struct{}

func (StderrLogger) Write(b []byte) (int, error) {
Debug(string(b))
return len(b), nil
}
29 changes: 21 additions & 8 deletions subprocesses/multimon/multimon.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,44 @@ import (
"bufio"
"io"
"os/exec"
"strings"

"github.com/cceremuga/ionosphere/services/config"
"github.com/cceremuga/ionosphere/services/log"
)

// Build builds the Command for multimon-ng based upon config and flags.
// Build the Command for multimon-ng based upon config and flags.
func Build(c *config.Multimon) *exec.Cmd {
args := []string{"-a", "AFSK1200", "-A", "-t", "raw", "-", c.AdditionalFlags}
requiredArgs := []string{
"-a",
"AFSK1200",
"-A",
"-t",
"raw",
}

userArgs := strings.Fields(c.AdditionalFlags)
args := append(requiredArgs, userArgs...)
args = append(args, "-")
return exec.Command(c.Path, args...)
}

// Start starts the multimon-ng subprocess.
func Start(m *exec.Cmd, f func(reader io.Reader)) {
stdout, err := m.StdoutPipe()
// Start the multimon-ng subprocess.
func Start(c *exec.Cmd, f func(reader io.Reader)) {
stdout, err := c.StdoutPipe()

if err != nil {
log.Fatalf("Error obtaining multimon-ng ouput: %s", err.Error())
log.Fatalf("Error reading multimon-ng stdout: %s", err.Error())
}

c.Stderr = log.StderrLogger{}

reader := bufio.NewReader(stdout)
go f(reader)

if err := m.Start(); err != nil {
if err := c.Start(); err != nil {
log.Fatalf("Error starting multimon-ng: %s", err.Error())
}

log.Println("Multimon-ng subprocess initialized.")
log.Debug("multimon-ng initialized.")
}
42 changes: 42 additions & 0 deletions subprocesses/rtlfm/rtlfm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Package rtlfm represents a subprocess for rtl_fm.
package rtlfm

import (
"os/exec"
"strings"

"github.com/cceremuga/ionosphere/services/config"
"github.com/cceremuga/ionosphere/services/log"
)

// Build the Command for rtl_fm based upon config and flags.
func Build(c *config.Rtl) *exec.Cmd {
requiredArgs := []string{
"-f",
c.Frequency,
"-s",
c.SampleRate,
"-l",
c.SquelchLevel,
"-g",
c.Gain,
"-p",
c.PpmError,
}

userArgs := strings.Fields(c.AdditionalFlags)
args := append(requiredArgs, userArgs...)
args = append(args, "-")
return exec.Command(c.Path, args...)
}

// Start the rtl_fm subprocess.
func Start(c *exec.Cmd) {
c.Stderr = log.StderrLogger{}

if err := c.Start(); err != nil {
log.Fatalf("Error starting rtl_fm: %s", err.Error())
}

log.Debug("rtl_fm initialized.")
}
25 changes: 0 additions & 25 deletions subprocesses/rtlsdr/rtlsdr.go

This file was deleted.

6 changes: 3 additions & 3 deletions tasks/beacon/beacon.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ func Start(c *config.Beacon) {
}

if !c.Enabled {
log.Println("Beacon inactive.")
log.Debug("Beacon inactive.")
return
}

startTicker(c)
}

func startTicker(c *config.Beacon) {
log.Println(fmt.Sprintf("Beacon active, will upload every %s", c.Interval))
log.Debug(fmt.Sprintf("Beacon active, will upload every %s", c.Interval))

ticker := time.NewTicker(c.Interval)
quit := make(chan struct{})
Expand All @@ -54,7 +54,7 @@ func tickerInterval(c *config.Beacon) {
Comment: c.Comment,
}
cyan := color.New(color.FgCyan).SprintFunc()
log.Println(fmt.Sprintf("%s %s", cyan("[TO APRS-IS]"), b.String()))
log.Info(fmt.Sprintf("%s %s", cyan("[TO APRS-IS]"), b.String()))
aprsis.UploadRaw(b.String())
}

Expand Down

0 comments on commit baee180

Please sign in to comment.