Files
ptb/main.go
2025-02-02 19:19:16 +01:00

193 lines
5.0 KiB
Go

package main
import (
"errors"
"flag"
"fmt"
"path/filepath"
//log "github.com/fangdingjun/go-log"
"log"
"os"
"os/signal"
"syscall"
"github.com/jroimartin/gocui"
"github.com/karanveersp/store"
"gopkg.in/yaml.v2"
)
const usage = `Usage of ptb - the PACTOR-IP-Bridge:
-c, --configfile string Name of config file (default "Config.yaml")
-d, --daemon Daemon mode (no TUI)
-l, --logfile string Path to the log file
`
const (
StatusTCPCmdActive uint8 = 1 << iota //00000001
StatusTCPDataActive //00000010
)
type TCPServer struct {
Protocol chan string
ToPactor *ByteFIFO
FromPactor *ByteFIFO
VARAMode bool
DaemonMode bool
Status uint8
Command struct {
Cmd *StringFIFO
Response *StringFIFO
}
Data struct {
Data *ByteFIFO
Response *ByteFIFO
}
}
func NewTCPServer(varamode bool, daemonmode bool) *TCPServer {
return &TCPServer{
Protocol: make(chan string, 1024),
ToPactor: NewByteFIFO(1024),
FromPactor: NewByteFIFO(1024),
VARAMode: varamode,
DaemonMode: daemonmode,
Status: 0,
Command: struct {
Cmd *StringFIFO
Response *StringFIFO
}{Cmd: NewStringFIFO(), Response: NewStringFIFO()},
Data: struct {
Data *ByteFIFO
Response *ByteFIFO
}{Data: NewByteFIFO(10240), Response: NewByteFIFO(10240)},
}
}
type Userconfig struct {
Device string `yaml:"device"`
Baudrate int `yaml:"baudrate"`
Mycall string `yaml:"mycall"`
ServerAddress string `yaml:"server_address"`
DataAddress string `yaml:"data_address"`
CmdLineInit string `yaml:"cmdline_init"`
StartwithVaraMode bool `yaml:"vara_mode"`
}
func configmanage(Config *Userconfig, path string) error {
cf := store.GetApplicationDirPath() + string(os.PathSeparator) + path
_, err := os.Stat(cf)
if err != nil {
log.Println("loadConfig error:", err)
log.Println("Config file not found. Creating new one")
Config = &Userconfig{Device: "/tmp/ttyUSB0",
Baudrate: 9600,
Mycall: "N0CALL",
ServerAddress: "127.0.0.1:8300",
DataAddress: "127.0.0.1:8301",
CmdLineInit: "",
StartwithVaraMode: false}
if err := store.Save("Config.yaml", Config); err != nil {
log.Println("failed to save the Config file: ", err)
return err
}
return errors.New(fmt.Sprintf("new Config file %s created. Please edit the Config file and restart the application", cf))
}
if err := store.Load(path, Config); err != nil {
return err
}
if Config.Device != "" {
//log.Println("Config loaded:", Config)
return nil
}
return errors.New(fmt.Sprintf("Empty device name in Config file. Please edit the Config file %s and restart the application", cf))
}
func init() {
store.Init("dl1thm.pactortcpbridge")
store.Register("ini", yaml.Marshal, yaml.Unmarshal)
}
var s *TCPServer // s is a pointer to TCPServer, managing communication via channels and FIFO queues for command and data handling.
func main() {
tmpfile := filepath.FromSlash(os.TempDir() + "/ptb.log")
// read command line arguments -- the standard flag module unfortunately doesn't know shorthands
var configfile string
flag.StringVar(&configfile, "configfile", "Config.yaml", "Name of config file")
flag.StringVar(&configfile, "c", "Config.yaml", "Name of config file")
var logfile string
flag.StringVar(&logfile, "logfile", tmpfile, "Name of log file")
flag.StringVar(&logfile, "l", tmpfile, "Name of log file")
var daemonMode bool
flag.BoolVar(&daemonMode, "daemon", false, "Daemon mode (no TUI)")
flag.BoolVar(&daemonMode, "d", false, "Daemon mode (no TUI)")
flag.Usage = func() { fmt.Print(usage) }
flag.Parse()
f, err := os.OpenFile(logfile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
defer f.Close()
log.SetOutput(f)
fmt.Println("logging to " + logfile)
// read config
var Config Userconfig
//c := store.GetApplicationDirPath()
err = configmanage(&Config, configfile)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
s = NewTCPServer(Config.StartwithVaraMode, daemonMode)
fmt.Println("Initializing PACTOR modem, please wait...")
m, err := OpenModem(Config.Device, Config.Baudrate, Config.Mycall, "", Config.CmdLineInit)
if err != nil {
log.Panicln(err)
}
defer m.Close()
go tcpCmdServer(&Config)
go tcpDataServer(&Config)
if !daemonMode {
// Initialize the gocui GUI
g, err := gocui.NewGui(gocui.OutputNormal)
if err != nil {
log.Panicln(err)
}
defer g.Close()
g.SetManagerFunc(layout)
go protocolUpdate(g)
go pactorUpdate(g)
go statusUpdate(g)
// Set keybindings
if err := keybindings(g); err != nil {
log.Panicln(err)
}
// Start the main TUI loop
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
log.Panicln(err)
}
} else {
// daemon mode: just print a message and wait for CTRL-C
done := make(chan os.Signal, 1)
signal.Notify(done, syscall.SIGINT, syscall.SIGTERM)
fmt.Println("pactortcpbridge running, press ctrl+c to end the process...")
<-done
}
}