diff --git a/fifo.go b/fifo.go index bdc4b1e..fa6b7c5 100644 --- a/fifo.go +++ b/fifo.go @@ -116,7 +116,7 @@ func (f *ByteFIFO) Peek(n int) ([]byte, error) { return f.buffer[:n], nil } -// Size returns the current number of bytes in the buffer. +// GetLen returns the current number of bytes in the buffer. func (f *ByteFIFO) GetLen() int { f.mutex.Lock() defer f.mutex.Unlock() @@ -137,7 +137,7 @@ type StringFIFO struct { cond *sync.Cond // Condition variable for signaling } -// NewByteFIFO creates a new ByteFIFO with the given capacity. +// NewStringFIFO creates a new StringFIFO. func NewStringFIFO() *StringFIFO { fifo := &StringFIFO{ buffer: make([]string, 0), @@ -147,13 +147,12 @@ func NewStringFIFO() *StringFIFO { } // Enqueue adds a string to the end of the buffer. Returns an error if the buffer is full. -func (f *StringFIFO) Enqueue(data string) error { +func (f *StringFIFO) Enqueue(data string) { f.mutex.Lock() defer f.mutex.Unlock() f.buffer = append(f.buffer, data) f.cond.Signal() // Notify waiting goroutines that data is available - return nil } // Dequeue removes and returns the first `n` bytes from the buffer (or what's left if n>len(f.buffer)). diff --git a/gpsd.go b/gpsd.go index ffcbd46..2b97efb 100644 --- a/gpsd.go +++ b/gpsd.go @@ -90,19 +90,24 @@ func ParseWatchMessage(input string) (*WatchMessage, error) { var msg WatchMessage if err := json.Unmarshal([]byte(jsonPart), &msg); err != nil { - return nil, fmt.Errorf("Fehler beim Parsen des JSON: %w", err) + return nil, fmt.Errorf("fehler beim Parsen des JSON: %w", err) } return &msg, nil } -func startGPSdTCPServer(gpsdaddress string) error { +func startGPSdTCPServer(gpsdaddress string) { listener, err := net.Listen("tcp", gpsdaddress) if err != nil { writeDebug(fmt.Sprintf("Error starting TCP server: %v\n", err), 0) - return err + return } - defer listener.Close() + defer func() { + err := listener.Close() + if err != nil { + writeDebug(err.Error(), 0) + } + }() writeDebug(fmt.Sprintf("TCP server started on port %s", gpsdaddress), 1) for { @@ -130,10 +135,13 @@ func isNetConnClosedErr(err error) bool { } func addClient(client net.Conn) { - if s.NMEAPassthrough { + if s.Userconfig.NMEAPassthrough { go func() { defer func() { - client.Close() + err := client.Close() + if err != nil { + writeDebug(err.Error(), 0) + } removeClient(client) writeDebug(fmt.Sprintf("GPSd Client disconnected: %v\n", client.RemoteAddr()), 0) }() @@ -151,7 +159,10 @@ func addClient(client net.Conn) { go func() { defer func() { - client.Close() + err := client.Close() + if err != nil { + writeDebug(err.Error(), 0) + } removeClient(client) writeDebug(fmt.Sprintf("GPSd Client disconnected: %v\n", client.RemoteAddr()), 0) }() @@ -160,7 +171,10 @@ func addClient(client net.Conn) { for { time.Sleep(100 * time.Millisecond) // looks like gpsd does not expect \n terminated lines so read what is there from the socket - client.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + err := client.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + if err != nil { + writeDebug(err.Error(), 0) + } buff := make([]byte, 1024) n, err := rd.Read(buff) if isNetConnClosedErr(err) { @@ -173,8 +187,8 @@ func addClient(client net.Conn) { } line := string(buff[:n]) - writeDebug(fmt.Sprintf("gpsd: Received from client: %v\n", string(line)), 1) - msg, err := ParseWatchMessage(string(line)) + writeDebug(fmt.Sprintf("gpsd: Received from client: %v\n", line), 1) + msg, err := ParseWatchMessage(line) if err == nil { // fill devices list @@ -236,7 +250,7 @@ func publishTPV() { func readAndBroadcast() { device := s.DeviceType - if s.NMEAPassthrough { + if s.Userconfig.NMEAPassthrough { for { nmeaSentence, err := s.GPSStream.DequeueOrWait() if err != nil { @@ -335,10 +349,10 @@ func updateTPVFromRMC(s nmea.RMC, device string) { currentTPV.Class = "TPV" currentTPV.Device = device currentTPV.Time = parseTime(s.Time.String()) - currentTPV.Lat = float64(s.Latitude) - currentTPV.Lon = float64(s.Longitude) - currentTPV.Speed = float64(s.Speed * knotsToMs) - currentTPV.Track = float64(s.Course) + currentTPV.Lat = s.Latitude + currentTPV.Lon = s.Longitude + currentTPV.Speed = s.Speed * knotsToMs + currentTPV.Track = s.Course // Now publish currentTPV to gpsd publishTPV() } @@ -347,9 +361,9 @@ func updateTPVFromGGA(s nmea.GGA, device string) { currentTPV.Class = "TPV" currentTPV.Device = device currentTPV.Time = parseTime(s.Time.String()) - currentTPV.Lat = float64(s.Latitude) - currentTPV.Lon = float64(s.Longitude) - currentTPV.Alt = float64(s.Altitude) + currentTPV.Lat = s.Latitude + currentTPV.Lon = s.Longitude + currentTPV.Alt = s.Altitude // Publish currentTPV to gpsd publishTPV() } @@ -358,9 +372,9 @@ func updateTPVFromGSA(s nmea.GSA) { // Update only the fields provided by GSA fixtype, _ := strconv.Atoi(s.FixType) currentTPV.Mode = fixtype - currentTPV.PDOP = float64(s.PDOP) - currentTPV.HDOP = float64(s.HDOP) - currentTPV.VDOP = float64(s.VDOP) + currentTPV.PDOP = s.PDOP + currentTPV.HDOP = s.HDOP + currentTPV.VDOP = s.VDOP // Publish currentTPV to gpsd publishTPV() } @@ -391,7 +405,10 @@ func broadcastToClients(message string) { _, err := client.Write([]byte(message + "\n")) if err != nil { writeDebug(fmt.Sprintf("gpsd: error writing to client %v: %v\n", client.RemoteAddr(), err), 0) - client.Close() + err = client.Close() + if err != nil { + writeDebug(err.Error(), 0) + } delete(clients, client) } writeDebug(fmt.Sprintf("gpsd: message: %v", message), 1) diff --git a/main.go b/main.go index c055231..75715a6 100644 --- a/main.go +++ b/main.go @@ -28,18 +28,17 @@ const ( ) type TCPServer struct { - Protocol chan string - ToPactor *ByteFIFO // used for the TUI - FromPactor *ByteFIFO // used for the TUI - ToTRX *ByteFIFO // TRX remote control - FromTRX *ByteFIFO // TRX remove control - VARAMode bool - DaemonMode bool - GPSdMode bool - NMEAPassthrough bool - DeviceType string - Status uint8 - Command struct { + Protocol chan string + ToPactor *ByteFIFO // used for the TUI + FromPactor *ByteFIFO // used for the TUI + ToTRX *ByteFIFO // TRX remote control + FromTRX *ByteFIFO // TRX remove control + Userconfig *Userconfig + VARAMode bool + DaemonMode bool + DeviceType string + Status uint8 + Command struct { Cmd *StringFIFO Response *StringFIFO } @@ -50,31 +49,6 @@ type TCPServer struct { GPSStream *StringFIFO // NMEA steam from PTC to gpsd server, see gpsd.go } -func NewTCPServer(varamode bool, daemonmode bool, gpsdmode bool, nmeapassthrough bool) *TCPServer { - return &TCPServer{ - Protocol: make(chan string, 1024), - ToPactor: NewByteFIFO(1024), - FromPactor: NewByteFIFO(1024), - ToTRX: NewByteFIFO(1024), - FromTRX: NewByteFIFO(1024), - VARAMode: varamode, - DaemonMode: daemonmode, - GPSdMode: gpsdmode, - NMEAPassthrough: nmeapassthrough, - DeviceType: "", - Status: 0, - Command: struct { - Cmd *StringFIFO - Response *StringFIFO - }{Cmd: NewStringFIFO(), Response: NewStringFIFO()}, - Data: struct { - Data *ByteFIFO - Response *ByteFIFO - }{Data: NewByteFIFO(10240), Response: NewByteFIFO(10240)}, - GPSStream: NewStringFIFO(), - } -} - type Userconfig struct { Device string `yaml:"device"` Baudrate int `yaml:"baudrate"` @@ -87,6 +61,30 @@ type Userconfig struct { StartwithVaraMode bool `yaml:"vara_mode"` } +func NewTCPServer(userconfig *Userconfig, daemonmode bool) *TCPServer { + return &TCPServer{ + Protocol: make(chan string, 1024), + ToPactor: NewByteFIFO(1024), + FromPactor: NewByteFIFO(1024), + ToTRX: NewByteFIFO(1024), + FromTRX: NewByteFIFO(1024), + Userconfig: userconfig, + VARAMode: userconfig.StartwithVaraMode, + DaemonMode: daemonmode, + DeviceType: "", + Status: 0, + Command: struct { + Cmd *StringFIFO + Response *StringFIFO + }{Cmd: NewStringFIFO(), Response: NewStringFIFO()}, + Data: struct { + Data *ByteFIFO + Response *ByteFIFO + }{Data: NewByteFIFO(10240), Response: NewByteFIFO(10240)}, + GPSStream: NewStringFIFO(), + } +} + func configmanage(Config *Userconfig, path string) error { cf := store.GetApplicationDirPath() + string(os.PathSeparator) + path @@ -151,7 +149,12 @@ func main() { if err != nil { log.Fatalf("error opening file: %v", err) } - defer f.Close() + defer func() { + err := f.Close() + if err != nil { + writeDebug(err.Error(), 0) + } + }() log.SetOutput(f) fmt.Println("logging to " + logfile) @@ -165,13 +168,18 @@ func main() { os.Exit(1) } - s = NewTCPServer(Config.StartwithVaraMode, daemonMode, Config.GPSdAddress != "", Config.NMEAPassthrough) + s = NewTCPServer(&Config, 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() + defer func() { + err := m.Close() + if err != nil { + writeDebug(err.Error(), 0) + } + }() go tcpCmdServer(&Config) go tcpDataServer(&Config) @@ -203,7 +211,7 @@ func main() { log.Panicln(err) } // Start the main TUI loop - if err := g.MainLoop(); err != nil && err != gocui.ErrQuit { + if err := g.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) { log.Panicln(err) } } else { diff --git a/ptc.go b/ptc.go index 994b5d7..7d9e69b 100644 --- a/ptc.go +++ b/ptc.go @@ -118,7 +118,7 @@ func writeDebug(message string, level int) { return } -// OpenModem: Initialise the pactor modem and all variables. Switch the modem into hostmode. +// OpenModem Initialise the pactor modem and all variables. Switch the modem into hostmode. // // Will abort if modem reports failed link setup, Close() is called or timeout // has occured (90 seconds) @@ -208,7 +208,7 @@ func (p *Modem) init() (err error) { } if len(ans) < 2 { - return errors.New("Modem does not react to Quit command. Please re-power your modem") + return errors.New("modem does not react to Quit command. Please re-power your modem") } // Check if we can determine the modem's type @@ -288,7 +288,12 @@ func (p *Modem) runInitScript(initScript string) error { if err != nil { return err } - defer file.Close() + defer func() { + err := file.Close() + if err != nil { + writeDebug(err.Error(), 0) + } + }() scanner := bufio.NewScanner(file) for scanner.Scan() { @@ -386,14 +391,20 @@ func (p *Modem) modemThread() { writeDebug("response: "+string(res)+"\n"+hex.Dump(res), 3) switch c { case PactorChannel: - s.Data.Response.Enqueue(res) + err := s.Data.Response.Enqueue(res) + if err != nil { + writeDebug(err.Error(), 0) + } writeDebug("Written to sendbuf", 3) case 254: //Status update p.chanbusy = int(res[0])&112 == 112 // See PTC-IIIusb manual "STATUS" command writeDebug("PACTOR state: "+strconv.FormatInt(int64(res[0]), 2), 2) case TRXControlChannel: //if !bytes.Equal(res, trxcmd) { - s.FromTRX.Enqueue(res) + err := s.FromTRX.Enqueue(res) + if err != nil { + writeDebug(err.Error(), 0) + } writeDebug("TRX CMD answer:\n"+hexdump.Dump(res), 1) //} default: @@ -448,19 +459,20 @@ func (p *Modem) stophostmode() { n, _, err := p.read(100) if err != nil { log.Fatal(err) - break } if n == 0 { break } } - p.write("\rRESTART\r") + err = p.write("\rRESTART\r") + if err != nil { + writeDebug(err.Error(), 0) + } time.Sleep(1000 * time.Millisecond) for { n, a, err := p.read(100) if err != nil { log.Fatal(err) - break } if n == 0 { break @@ -525,11 +537,6 @@ func (p *Modem) close() (err error) { return nil } -// Set specified flag (channel) -func setFlag(flag chan struct{}) { - flag <- struct{}{} -} - // Get number of frames not yet transmitted by the modem func (p *Modem) getNumFramesNotTransmitted() int { //return p.channelState.c @@ -542,7 +549,7 @@ func (p *Modem) getNumFrameNotAck() int { return 0 } -// Check if serial device is still available (e.g still connected) +// Check if serial device is still available (e.g. still connected) func (p *Modem) checkSerialDevice() (err error) { if _, err := os.Stat(p.devicePath); os.IsNotExist(err) { return fmt.Errorf("ERROR: Device %s does not exist", p.devicePath) @@ -578,7 +585,7 @@ func (p *Modem) getChannelsWithOutput() (channels []int, err error) { // Currently, only connection information (payload) messages are passed on func (p *Modem) checkResponse(resp string, ch int) (n int, data []byte, err error) { if len(resp) < 3 { - return 0, nil, fmt.Errorf("No data") + return 0, nil, fmt.Errorf("no data") } head := []byte(resp[:3]) @@ -587,11 +594,11 @@ func (p *Modem) checkResponse(resp string, ch int) (n int, data []byte, err erro pl := len(payload) if int(head[0]) != ch { writeDebug("WARNING: Returned data does not match polled channel\n"+hex.Dump([]byte(resp)), 1) - return 0, nil, fmt.Errorf("Channel missmatch") + return 0, nil, fmt.Errorf("channel missmatch") } if int(head[1]) == 1 { //sucess,message follows writeDebug(fmt.Sprintf("*** SUCCESS on channel %d: %s", ch, string(payload)), 1) - if ch == NMEAChannel && s.GPSdMode { + if ch == NMEAChannel && s.Userconfig.GPSdAddress != "" { if s.GPSStream.GetLen() == 0 { s.GPSStream.Enqueue("$" + string(bytes.Trim(payload, "\x00"))) //need to remove the trailing NULL byte } @@ -611,7 +618,7 @@ func (p *Modem) checkResponse(resp string, ch int) (n int, data []byte, err erro s.Command.Response.Enqueue(fmt.Sprintf("%s\n", payload)) } writeDebug("Message from Modem: "+string(payload), 1) - return 0, nil, fmt.Errorf("Not a data response") + return 0, nil, fmt.Errorf("not a data response") } if int(head[1]) == 3 { //Link status if !s.VARAMode { @@ -648,7 +655,7 @@ func (p *Modem) checkResponse(resp string, ch int) (n int, data []byte, err erro //p.channelState.f = 0 return 0, nil, nil } - return 0, nil, fmt.Errorf("Link data") + return 0, nil, fmt.Errorf("link data") } if length != pl { writeDebug("WARNING: Data length "+strconv.Itoa(pl)+" does not match stated amount "+strconv.Itoa(length)+". After "+strconv.Itoa(p.goodChunks)+" good chunks.", 1) @@ -711,7 +718,7 @@ func (p *Modem) writeAndGetResponse(msg string, ch int, isCommand bool, chunkSiz } time.Sleep(50 * time.Millisecond) writeDebug("Decode WA8DED", 4) - buf := []byte{} + var buf []byte valid := false for valid == false { @@ -728,7 +735,7 @@ func (p *Modem) writeAndGetResponse(msg string, ch int, isCommand bool, chunkSiz if err != nil { writeDebug("ERROR at _read: "+error.Error(err), 1) } - writeDebug("Len: "+strconv.Itoa(len(buf))+"State: "+string(hex.Dump(buf)+"\n"), 4) + writeDebug("Len: "+strconv.Itoa(len(buf))+" State: "+hex.Dump(buf)+"\n", 4) if br > 0 { //we got some data buf = append(buf, b...) @@ -780,15 +787,10 @@ func (p *Modem) Busy() bool { // Although these functions are small, I prefer to keep their functionality // separate. They follow the steps in the SCS documentation -// printhex: helper function: de-hexlify and write to debug channel -func printhex(s string) { - t, _ := hex.DecodeString(s) - writeDebug(string(t), 3) -} - +/* // unstuff: helper function: "unstuff" a string func unstuff(s string) string { - //Expect: the string contains aa aa at the beginning, that should NOT be + //Expect: the string contains "aa aa" at the beginning, that should NOT be //stuffed n, _ := hex.DecodeString(s[4:]) n = bytes.Replace(n, []byte{170, 0}, []byte{170}, -1) @@ -797,14 +799,16 @@ func unstuff(s string) string { re := hex.EncodeToString(r) return re } +*/ +/* // stuff: helper function: "stuff" a string: replaces every #170 with #170#0 func stuff(s string) string { - //Expect: the string contains aa aa at the beginning, that should NOT be + //Expect: the string contains "aa aa" at the beginning, that should NOT be //stuffed n, err := hex.DecodeString(s[4:]) if err != nil { - writeDebug("ERROR in Stuff: "+err.Error()+"\n"+string(hex.Dump([]byte(s))), 1) + writeDebug("ERROR in Stuff: "+err.Error()+"\n"+hex.Dump([]byte(s)), 1) } n = bytes.Replace(n, []byte{170}, []byte{170, 0}, -1) @@ -813,22 +817,26 @@ func stuff(s string) string { re := hex.EncodeToString(r) return re } +*/ +/* // checksum: helper function: calculates the CCITT-CRC16 checksum func checksum(s string) uint16 { tochecksum, _ := hex.DecodeString(s[4:]) - chksum := bits.ReverseBytes16(crc16.ChecksumCCITT([]byte(tochecksum))) + chksum := bits.ReverseBytes16(crc16.ChecksumCCITT(tochecksum)) return chksum } +*/ // checkcrc: helper fuction: check the checksum by comparing func checkcrc(s []byte) bool { tochecksum := s[2 : len(s)-2] chksum := bits.ReverseBytes16(crc16.ChecksumCCITT(tochecksum)) pksum := s[len(s)-2:] - return (binary.BigEndian.Uint16(pksum) == chksum) + return binary.BigEndian.Uint16(pksum) == chksum } +/* // docrc: super helper fuction: convert an ordinary WA8DED message into a CRC-Hostmode message func docrc(msg string) string { // step 1: add a #170170 @@ -839,8 +847,8 @@ func docrc(msg string) string { // step 3: add "stuff" bytes msg = stuff(msg) return msg - } +*/ // writeChannel: Write channel to serial connection (NOT thread safe)- If used, make sure to mutex! func (p *Modem) writeChannel(msg string, ch int, isCommand bool) error { @@ -861,7 +869,7 @@ func (p *Modem) writeChannel(msg string, ch int, isCommand bool) error { d = byte(0x81) } - var o []byte = []byte{170, 170, byte(ch), byte(d), byte((len(msg) - 1))} + o := []byte{170, 170, byte(ch), d, byte(len(msg) - 1)} o = append(o, []byte(msg)...) cksum := bits.ReverseBytes16(crc16.ChecksumCCITT(o[2:])) cksumb := make([]byte, 2) @@ -913,7 +921,10 @@ func (p *Modem) read(readsize int) (int, []byte, error) { } buf := make([]byte, chunkSize) if strings.HasPrefix(p.devicePath, "tcp://") { - p.tcpdevice.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + err := p.tcpdevice.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + if err != nil { + writeDebug(err.Error(), 0) + } n, err := p.tcpdevice.Read(buf) if err != nil { writeDebug("Error received during read: "+err.Error(), 1) @@ -928,7 +939,10 @@ func (p *Modem) read(readsize int) (int, []byte, error) { p.mux.device.Lock() defer p.mux.device.Unlock() - p.device.SetReadTimeout(100) // 100 ms + err := p.device.SetReadTimeout(100) // 100 ms + if err != nil { + writeDebug(err.Error(), 0) + } n, err := p.device.Read(buf) if err != nil { writeDebug("Error received during read: "+err.Error(), 1) diff --git a/tcpserver.go b/tcpserver.go index 963974f..7df5577 100644 --- a/tcpserver.go +++ b/tcpserver.go @@ -22,7 +22,7 @@ func Chunks(s string, chunkSize int) []string { if chunkSize >= len(s) { return []string{s} } - var chunks []string = make([]string, 0, (len(s)-1)/chunkSize+1) + chunks := make([]string, 0, (len(s)-1)/chunkSize+1) currentLen := 0 currentStart := 0 for i := range s { @@ -41,7 +41,10 @@ func Chunks(s string, chunkSize int) []string { func handleTCPCmdConnection(conn net.Conn) { defer func() { s.Status &^= StatusTCPCmdActive - conn.Close() + err := conn.Close() + if err != nil { + writeDebug(err.Error(), 0) + } }() s.Status |= StatusTCPCmdActive @@ -83,7 +86,10 @@ func handleTCPCmdConnection(conn net.Conn) { return } else { s.Protocol <- fmt.Sprintf(color.InCyan("Response: %s\n"), msg) - conn.Write([]byte(fmt.Sprintf("%s\r", msg))) + _, err = conn.Write([]byte(fmt.Sprintf("%s\r", msg))) + if err != nil { + writeDebug(err.Error(), 0) + } } } }(ctx) @@ -98,7 +104,10 @@ func handleTCPCmdConnection(conn net.Conn) { alivecancel() //buffercancel() cancel() - conn.Close() + err = conn.Close() + if err != nil { + writeDebug(err.Error(), 0) + } break } @@ -138,7 +147,10 @@ func handleTCPCmdConnection(conn net.Conn) { func handleTCPDataConnection(conn net.Conn) { defer func() { s.Status &^= StatusTCPDataActive - conn.Close() + err := conn.Close() + if err != nil { + writeDebug(err.Error(), 0) + } }() s.Protocol <- fmt.Sprintf(color.InGreen("TCP Data Connection established with %s\n"), conn.RemoteAddr()) @@ -154,9 +166,15 @@ func handleTCPDataConnection(conn net.Conn) { } else { //TODO: VARA if !s.DaemonMode { - s.FromPactor.Enqueue(msg) + err := s.FromPactor.Enqueue(msg) + if err != nil { + writeDebug(err.Error(), 0) + } + } + _, err = conn.Write(msg) + if err != nil { + writeDebug(err.Error(), 0) } - conn.Write(msg) } } }() @@ -171,7 +189,10 @@ func handleTCPDataConnection(conn net.Conn) { if err != nil { s.Status &^= StatusTCPDataActive cancel() - conn.Close() + err := conn.Close() + if err != nil { + writeDebug(err.Error(), 0) + } return } //TODO: muss das nicht weg? @@ -180,15 +201,24 @@ func handleTCPDataConnection(conn net.Conn) { } */ if !s.DaemonMode { - s.ToPactor.Enqueue(temp) + err := s.ToPactor.Enqueue(temp) + if err != nil { + writeDebug(err.Error(), 0) + } } if n > 255 { // we can dump at max 255 bytes into for _, ck := range Chunks(string(temp), 255) { - s.Data.Data.Enqueue([]byte(ck)) + err := s.Data.Data.Enqueue([]byte(ck)) + if err != nil { + writeDebug(err.Error(), 0) + } } } else { - s.Data.Data.Enqueue(temp) + err := s.Data.Data.Enqueue(temp) + if err != nil { + writeDebug(err.Error(), 0) + } } } } @@ -199,7 +229,7 @@ func processVARACommand(command string) (string, string, error) { case strings.HasPrefix(command, "CONNECT"): re, err := regexp.MatchString(`CONNECT \w+ \w+`, command) if err != nil || !re { - return "", "", errors.New("Error matching regex") + return "", "", errors.New("error matching regex") } c := strings.Split(command, " ") return fmt.Sprintf("C %s", c[2]), "", nil @@ -220,7 +250,7 @@ func processVARACommand(command string) (string, string, error) { if strings.HasSuffix(command, "OFF") { return "%L 0", "", nil } - return "", "", errors.New("Neither ON nor OFF after LISTEN") + return "", "", errors.New("neither ON nor OFF after LISTEN") case strings.HasPrefix(command, "MYCALL"): m := "" @@ -230,7 +260,7 @@ func processVARACommand(command string) (string, string, error) { // send own callsign to PACTOR controller m = s[1] } else { - return "", "", errors.New("Invalid MYCALL command") + return "", "", errors.New("invalid MYCALL command") } return fmt.Sprintf("%s%s", "I ", m), "", nil @@ -267,7 +297,7 @@ func processVARACommand(command string) (string, string, error) { default: // Handle unrecognized commands - return "", "", errors.New("Unknown command") + return "", "", errors.New("unknown command") } } @@ -279,7 +309,12 @@ func tcpCmdServer(Config *Userconfig) { log.Println(err) return } - defer listener.Close() + defer func() { + err := listener.Close() + if err != nil { + writeDebug(err.Error(), 0) + } + }() s.Protocol <- fmt.Sprintf("TCP Protocol Server listening on %s\n", Config.ServerAddress) @@ -303,7 +338,12 @@ func tcpDataServer(Config *Userconfig) { log.Println(err) return } - defer listener.Close() + defer func() { + err := listener.Close() + if err != nil { + writeDebug(err.Error(), 0) + } + }() s.Protocol <- fmt.Sprintf("TCP Data Server listening on %s\n", Config.DataAddress) for { diff --git a/trxcontrol.go b/trxcontrol.go index d0004f4..3f1aed7 100644 --- a/trxcontrol.go +++ b/trxcontrol.go @@ -16,8 +16,18 @@ func trxControl() { if err != nil { writeDebug(fmt.Sprintf("trxControl: error opening PTY: %v", err), 0) } - defer master.Close() - defer slave.Close() + defer func() { + err := master.Close() + if err != nil { + writeDebug(fmt.Sprintf("trxControl: error closing PTY: %v", err), 0) + } + }() + defer func() { + err := slave.Close() + if err != nil { + writeDebug(fmt.Sprintf("trxControl: error closing PTY: %v", err), 0) + } + }() err = os.Remove(ptypath) if err := os.Symlink(slave.Name(), ptypath); err != nil { @@ -29,8 +39,11 @@ func trxControl() { for { cmd, err := s.FromTRX.Dequeue(1024) if err == nil { - master.Write(cmd) writeDebug("From TRX response ("+strconv.Itoa(len(cmd))+"):\n"+hexdump.Dump(cmd), 1) + _, err = master.Write(cmd) + if err != nil { + writeDebug(fmt.Sprintf("trxControl: error writing to PTY: %v", err), 0) + } } time.Sleep(30 * time.Millisecond) } @@ -43,7 +56,10 @@ func trxControl() { for { time.Sleep(100 * time.Millisecond) // looks like gpsd does not expect \n terminated lines so read what is there from the socket - master.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + err := master.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + if err != nil { + writeDebug(fmt.Sprintf("trxControl: error setting read deadline: %v", err), 0) + } buff := make([]byte, 1024) n, err := rd.Read(buff) t := buff[:n] diff --git a/tui.go b/tui.go index e285050..5942298 100644 --- a/tui.go +++ b/tui.go @@ -1,23 +1,23 @@ package main import ( + "errors" "fmt" "github.com/TwiN/go-color" "github.com/jroimartin/gocui" - "log" "strings" "time" "unicode" ) func printable(r rune) rune { - if r == rune('\u000d') || r == rune('\u000a') { // ctrl-r or ctrl-n - return rune('\u000a') //ctrl-n + if r == '\u000d' || r == '\u000a' { // ctrl-r or ctrl-n + return '\u000a' //ctrl-n } if unicode.IsGraphic(r) { return r } - return rune('\u002e') // dot + return '\u002e' // dot } func Ternary(condition bool, valueIfTrue, valueIfFalse interface{}) interface{} { @@ -33,7 +33,7 @@ func layout(g *gocui.Gui) error { // "data" view: Top-left large view if v, err := g.SetView("data", 0, 0, lwX-1, maxY/2-1); err != nil { - if err != gocui.ErrUnknownView { + if !errors.Is(err, gocui.ErrUnknownView) { return err } v.Title = "Data" @@ -43,7 +43,7 @@ func layout(g *gocui.Gui) error { // "protocol" view: Bottom-left large view if v, err := g.SetView("protocol", 0, maxY/2, lwX-1, maxY-1); err != nil { - if err != gocui.ErrUnknownView { + if !errors.Is(err, gocui.ErrUnknownView) { return err } v.Title = "Protocol" @@ -53,7 +53,7 @@ func layout(g *gocui.Gui) error { // "status" view: Smaller view on the right if v, err := g.SetView("status", lwX, 0, maxX-1, maxY-1); err != nil { - if err != gocui.ErrUnknownView { + if !errors.Is(err, gocui.ErrUnknownView) { return err } v.Title = "Status" @@ -79,10 +79,13 @@ func protocolUpdate(g *gocui.Gui) { g.Update(func(g *gocui.Gui) error { v, err := g.View("protocol") if err != nil { - log.Println(err.Error()) + writeDebug(err.Error(), 0) return err } - fmt.Fprint(v, msg) + _, err = fmt.Fprint(v, msg) + if err != nil { + writeDebug(err.Error(), 0) + } return nil }) } @@ -93,32 +96,38 @@ func pactorUpdate(g *gocui.Gui) { if s.ToPactor.GetLen() > 0 { msg, err := s.ToPactor.Dequeue(256) if err != nil { - log.Println(err.Error()) + writeDebug(err.Error(), 0) continue } g.Update(func(g *gocui.Gui) error { v, err := g.View("data") if err != nil { - log.Println(err.Error()) + writeDebug(err.Error(), 0) return err } - fmt.Fprint(v, strings.Map(printable, string(msg))) + _, err = fmt.Fprint(v, strings.Map(printable, string(msg))) + if err != nil { + writeDebug(err.Error(), 0) + } return nil }) } if s.FromPactor.GetLen() > 0 { msg, err := s.FromPactor.Dequeue(256) if err != nil { - log.Println(err.Error()) + writeDebug(err.Error(), 0) continue } g.Update(func(g *gocui.Gui) error { v, err := g.View("data") if err != nil { - log.Println(err.Error()) + writeDebug(err.Error(), 0) return err } - fmt.Fprint(v, color.InRed(strings.Map(printable, string(msg)))) + _, err = fmt.Fprint(v, color.InRed(strings.Map(printable, string(msg)))) + if err != nil { + writeDebug(err.Error(), 0) + } return nil }) } @@ -132,25 +141,40 @@ func statusUpdate(g *gocui.Gui) { g.Update(func(g *gocui.Gui) error { v, err := g.View("status") if err != nil { - log.Println(err.Error()) + writeDebug(err.Error(), 0) } else { v.Clear() - fmt.Fprintln(v, time.Now().Format("15:04:05")) - fmt.Fprintln(v, Ternary(s.VARAMode, "VARA", "TCP")) - fmt.Fprintln(v, Ternary(s.Status&StatusTCPCmdActive != 0, color.InGreen("TCP CMD"), color.InRed("TCP CMD"))) - fmt.Fprintln(v, Ternary(s.Status&StatusTCPDataActive != 0, color.InGreen("TCP DATA"), color.InRed("TCP DATA"))) - fmt.Fprintln(v, fmt.Sprintf("\nCMD S: %d\nCMD R: %d\nDTA S: %d\nDTA R: %d", s.Command.Cmd.GetLen(), s.Command.Response.GetLen(), s.Data.Data.GetLen(), s.Data.Response.GetLen())) + _, err := fmt.Fprintln(v, time.Now().Format("15:04:05")) + if err != nil { + writeDebug(err.Error(), 0) + } + _, err = fmt.Fprintln(v, Ternary(s.VARAMode, "VARA", "TCP")) + if err != nil { + writeDebug(err.Error(), 0) + } + _, err = fmt.Fprintln(v, Ternary(s.Status&StatusTCPCmdActive != 0, color.InGreen("TCP CMD"), color.InRed("TCP CMD"))) + if err != nil { + writeDebug(err.Error(), 0) + } + _, err = fmt.Fprintln(v, Ternary(s.Status&StatusTCPDataActive != 0, color.InGreen("TCP DATA"), color.InRed("TCP DATA"))) + if err != nil { + writeDebug(err.Error(), 0) + } + _, err = fmt.Fprintln(v, fmt.Sprintf("\nCMD S: %d\nCMD R: %d\nDTA S: %d\nDTA R: %d", s.Command.Cmd.GetLen(), s.Command.Response.GetLen(), s.Data.Data.GetLen(), s.Data.Response.GetLen())) + if err != nil { + writeDebug(err.Error(), 0) + } } return nil }) } } -func quit(g *gocui.Gui, v *gocui.View) error { +func quit(_ *gocui.Gui, _ *gocui.View) error { return gocui.ErrQuit } -func toggleMode(g *gocui.Gui, v *gocui.View) error { +func toggleMode(_ *gocui.Gui, _ *gocui.View) error { s.Protocol <- fmt.Sprintf(color.InPurple("Toggle mode\n")) s.VARAMode = !s.VARAMode return nil