diff --git a/go.mod b/go.mod index 5cc79df..657f86c 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,9 @@ require ( require ( github.com/BurntSushi/toml v1.2.1 // indirect + github.com/augustoroman/hexdump v0.0.0-20231204223853-3694912baadb // indirect github.com/creack/goselect v0.1.2 // indirect + github.com/creack/pty v1.1.24 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/nsf/termbox-go v1.1.1 // indirect diff --git a/main.go b/main.go index 1a8ce1e..57547d9 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,6 @@ import ( "fmt" "path/filepath" - //log "github.com/fangdingjun/go-log" "log" "os" "os/signal" @@ -32,6 +31,8 @@ type TCPServer struct { Protocol chan string ToPactor *ByteFIFO FromPactor *ByteFIFO + ToTRX *ByteFIFO + FromTRX *ByteFIFO VARAMode bool DaemonMode bool GPSdMode bool @@ -54,6 +55,8 @@ func NewTCPServer(varamode bool, daemonmode bool, gpsdmode bool, nmeapassthrough Protocol: make(chan string, 1024), ToPactor: NewByteFIFO(1024), FromPactor: NewByteFIFO(1024), + ToTRX: NewByteFIFO(1024), + FromTRX: NewByteFIFO(1024), VARAMode: varamode, DaemonMode: daemonmode, GPSdMode: gpsdmode, @@ -178,6 +181,10 @@ func main() { go readAndBroadcast() } + if true { // TODO: later change to Config + go trxControl() + } + if !daemonMode { // Initialize the gocui GUI g, err := gocui.NewGui(gocui.OutputNormal) diff --git a/ptc.go b/ptc.go index 2a1e5cd..994b5d7 100644 --- a/ptc.go +++ b/ptc.go @@ -9,6 +9,7 @@ import ( "fmt" "github.com/TwiN/go-color" "github.com/albenik/go-serial/v2" + "github.com/augustoroman/hexdump" "log" "math" "math/bits" @@ -75,11 +76,12 @@ type Modem struct { } const ( - SerialTimeout = 1 - PactorChannel = 4 - NMEAChannel = 249 - MaxSendData = 255 - MaxFrameNotTX = 2 + SerialTimeout = 1 + PactorChannel = 4 + NMEAChannel = 249 + TRXControlChannel = 253 + MaxSendData = 255 + MaxFrameNotTX = 2 ) // ToPactor states @@ -226,7 +228,9 @@ func (p *Modem) init() (err error) { } writeDebug("Found a "+modem+" modem at "+p.devicePath, 0) s.DeviceType = modem + writeDebug("Running init commands", 1) + ct := time.Now() commands := []string{"DD", "RESTART", "MYcall " + p.localAddr, "PTCH " + strconv.Itoa(PactorChannel), "MAXE 35", "REM 0", "CHOB 0", "PD 1", @@ -353,6 +357,22 @@ func (p *Modem) modemThread() { // TODO: Catch errors! } + // TX TRX control data + + trxcmd, err := s.ToTRX.Dequeue(1024) + if err == nil { + writeDebug("Write TRX command ("+strconv.Itoa(len(trxcmd))+"): "+hexdump.Dump(trxcmd), 1) + _, _, err := p.writeAndGetResponse(string(trxcmd), TRXControlChannel, false, chunkSize) + if err != nil { + writeDebug("Error when sending TRX Command: "+err.Error(), 0) + } + /*if len(ans) > 2 { + s.FromTRX.Enqueue([]byte(ans[2:])) + }*/ + //s.FromTRX.Enqueue([]byte(ans)) + //writeDebug("TRX CMD answer from modem: \n"+hexdump.Dump([]byte(ans)), 1) + } + // RX var res []byte @@ -371,6 +391,11 @@ func (p *Modem) modemThread() { 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) + writeDebug("TRX CMD answer:\n"+hexdump.Dump(res), 1) + //} default: writeDebug("Channel "+strconv.Itoa(c)+": "+string(res), 1) } @@ -571,6 +596,11 @@ func (p *Modem) checkResponse(resp string, ch int) (n int, data []byte, err erro s.GPSStream.Enqueue("$" + string(bytes.Trim(payload, "\x00"))) //need to remove the trailing NULL byte } } + /* if ch == TRXControlChannel { + writeDebug("TRX Control channel message: "+string(payload), 1) + s.FromTRX.Enqueue(payload) + } + */ } if int(head[1]) == 2 { diff --git a/trxcontrol.go b/trxcontrol.go new file mode 100644 index 0000000..d0004f4 --- /dev/null +++ b/trxcontrol.go @@ -0,0 +1,58 @@ +package main + +import ( + "bufio" + "fmt" + "github.com/augustoroman/hexdump" + "github.com/creack/pty" + "os" + "strconv" + "time" +) + +func trxControl() { + ptypath := "/tmp/my_virtual_serial" + master, slave, err := pty.Open() + if err != nil { + writeDebug(fmt.Sprintf("trxControl: error opening PTY: %v", err), 0) + } + defer master.Close() + defer slave.Close() + + err = os.Remove(ptypath) + if err := os.Symlink(slave.Name(), ptypath); err != nil { + writeDebug(fmt.Sprintf("trxControl: error creating link: %v", err), 0) + } + writeDebug(fmt.Sprintf("trxControl: opening PTY: %s\n", ptypath), 0) + // Receive from TRX + go func() { + 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) + } + time.Sleep(30 * time.Millisecond) + } + }() + + //scanner := bufio.NewScanner(master) + //for scanner.Scan() { + //t := scanner.Text() + rd := bufio.NewReader(master) + 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)) + buff := make([]byte, 1024) + n, err := rd.Read(buff) + t := buff[:n] + writeDebug("To TRX data ("+strconv.Itoa(len(t))+"):\n"+hexdump.Dump(t), 1) + // Send to TRX + err = s.ToTRX.Enqueue(t) + if err != nil { + writeDebug(fmt.Sprintf("trxControl: error enqueuing command: %v", err), 0) + } + + } +}