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