Option to use a TCP socket instead of a serial port. Closes #2.
This commit is contained in:
213
ptc.go
213
ptc.go
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/albenik/go-serial/v2"
|
||||
"log"
|
||||
"math/bits"
|
||||
"net"
|
||||
"os"
|
||||
"regexp"
|
||||
"runtime"
|
||||
@@ -46,13 +47,10 @@ type pflags struct {
|
||||
|
||||
type pmux struct {
|
||||
device sync.Mutex
|
||||
pactor sync.Mutex
|
||||
write sync.Mutex
|
||||
read sync.Mutex
|
||||
close sync.Mutex
|
||||
bufLen sync.Mutex
|
||||
// sendbuf sync.Mutex
|
||||
// recvbuf sync.Mutex
|
||||
}
|
||||
|
||||
type Modem struct {
|
||||
@@ -63,14 +61,12 @@ type Modem struct {
|
||||
|
||||
state State
|
||||
|
||||
device *serial.Port
|
||||
mux pmux
|
||||
wg sync.WaitGroup
|
||||
flags pflags
|
||||
goodChunks int
|
||||
// recvBuf bytes.Buffer
|
||||
// cmdBuf chan string
|
||||
// sendBuf bytes.Buffer
|
||||
device *serial.Port
|
||||
tcpdevice net.Conn
|
||||
mux pmux
|
||||
wg sync.WaitGroup
|
||||
flags pflags
|
||||
goodChunks int
|
||||
packetcounter bool
|
||||
chanbusy bool
|
||||
cmdlineinit string
|
||||
@@ -149,17 +145,24 @@ func OpenModem(path string, baudRate int, myCall string, initfile string, cmdlin
|
||||
}
|
||||
|
||||
writeDebug("Initialising pactor modem", 1)
|
||||
if err := p.checkSerialDevice(); err != nil {
|
||||
writeDebug(err.Error(), 1)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//Setup serial device
|
||||
if p.device, err = serial.Open(p.devicePath, serial.WithBaudrate(baudRate), serial.WithReadTimeout(SerialTimeout)); err != nil {
|
||||
writeDebug(err.Error(), 1)
|
||||
return nil, err
|
||||
if strings.HasPrefix(p.devicePath, "tcp://") {
|
||||
if p.tcpdevice, err = net.Dial("tcp", strings.Replace(p.devicePath, "tcp://", "", 1)); err != nil {
|
||||
writeDebug(err.Error(), 0)
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// Check if serial device exists
|
||||
if err := p.checkSerialDevice(); err != nil {
|
||||
writeDebug(err.Error(), 0)
|
||||
return nil, err
|
||||
}
|
||||
//Setup serial device
|
||||
if p.device, err = serial.Open(p.devicePath, serial.WithBaudrate(baudRate), serial.WithReadTimeout(SerialTimeout)); err != nil {
|
||||
writeDebug(err.Error(), 1)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = p.init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -410,10 +413,11 @@ func (p *Modem) stophostmode() {
|
||||
|
||||
for ok == false {
|
||||
buff := make([]byte, 100)
|
||||
p.device.Write([]byte{0xaa, 0xaa, 0x00, 0x01, 0x05, 0x4a, 0x48, 0x4f, 0x53, 0x54, 0x30, 0xfb, 0x3d})
|
||||
//var n int
|
||||
_ = p.write(string([]byte{0xaa, 0xaa, 0x00, 0x01, 0x05, 0x4a, 0x48, 0x4f, 0x53, 0x54, 0x30, 0xfb, 0x3d}))
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
for {
|
||||
n, err := p.device.Read(buff)
|
||||
n, _, err := p.read(100)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
break
|
||||
@@ -421,12 +425,11 @@ func (p *Modem) stophostmode() {
|
||||
if n == 0 {
|
||||
break
|
||||
}
|
||||
//fmt.Printf("%v", string(buff[:n]))
|
||||
}
|
||||
p.device.Write([]byte("\rRESTART\r"))
|
||||
p.write("\rRESTART\r")
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
for {
|
||||
n, err := p.device.Read(buff)
|
||||
n, a, err := p.read(100)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
break
|
||||
@@ -434,6 +437,7 @@ func (p *Modem) stophostmode() {
|
||||
if n == 0 {
|
||||
break
|
||||
}
|
||||
copy(buff, a)
|
||||
//fmt.Printf("%v", string(buff[:n]))
|
||||
}
|
||||
ok, err = regexp.Match("cmd:", buff)
|
||||
@@ -481,16 +485,12 @@ func (p *Modem) close() (err error) {
|
||||
writeDebug("PACTOR close called", 1)
|
||||
}
|
||||
|
||||
//p.disconnect()
|
||||
writeDebug("signal modem thread to stop", 1)
|
||||
p.flags.stopmodem = true
|
||||
writeDebug("waiting for all threads to exit", 1)
|
||||
p.wg.Wait()
|
||||
writeDebug("modem thread stopped", 1)
|
||||
|
||||
//p.hostmodeQuit()
|
||||
// will not close the serial port as we reuse it
|
||||
//p.device.Close()
|
||||
p.stophostmode()
|
||||
p.setState(Closed)
|
||||
writeDebug("PACTOR close() finished", 1)
|
||||
@@ -641,7 +641,7 @@ func (p *Modem) writeAndGetResponse(msg string, ch int, isCommand bool, chunkSiz
|
||||
var n int
|
||||
var str string
|
||||
if ch < 0 {
|
||||
err = p._write(msg + "\r")
|
||||
err = p.write(msg + "\r")
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
@@ -649,7 +649,7 @@ func (p *Modem) writeAndGetResponse(msg string, ch int, isCommand bool, chunkSiz
|
||||
i := 0
|
||||
var tmp []byte
|
||||
for {
|
||||
n, tmp, err = p._read(chunkSize)
|
||||
n, tmp, err = p.read(chunkSize)
|
||||
str = string(tmp)
|
||||
if err == nil {
|
||||
break
|
||||
@@ -685,7 +685,7 @@ func (p *Modem) writeAndGetResponse(msg string, ch int, isCommand bool, chunkSiz
|
||||
return 0, "", err
|
||||
}
|
||||
}
|
||||
br, b, err := p._read(1)
|
||||
br, b, err := p.read(1)
|
||||
if err != nil {
|
||||
writeDebug("ERROR at _read: "+error.Error(err), 1)
|
||||
}
|
||||
@@ -737,56 +737,6 @@ func (p *Modem) Busy() bool {
|
||||
return p.chanbusy
|
||||
}
|
||||
|
||||
// Write to serial connection (thread safe)
|
||||
//
|
||||
// No other read/write operation allowed during this time
|
||||
func (p *Modem) write(cmd string) error {
|
||||
p.mux.pactor.Lock()
|
||||
defer p.mux.pactor.Unlock()
|
||||
return p._write(cmd)
|
||||
}
|
||||
|
||||
// Write to serial connection (NOT thread safe)
|
||||
//
|
||||
// If used, make shure to lock/unlock p.mux.pactor mutex!
|
||||
func (p *Modem) _write(cmd string) error {
|
||||
if err := p.checkSerialDevice(); err != nil {
|
||||
writeDebug(err.Error(), 1)
|
||||
return err
|
||||
}
|
||||
|
||||
writeDebug("write: \n"+hex.Dump([]byte(cmd)), 3)
|
||||
|
||||
p.mux.device.Lock()
|
||||
defer p.mux.device.Unlock()
|
||||
out := cmd + "\r"
|
||||
for {
|
||||
|
||||
// check if the serial line is clear-to-send
|
||||
status, err := cts(p.device)
|
||||
if err != nil {
|
||||
writeDebug("GetModemStatusBits failed. cmd: "+cmd+" Error: "+err.Error(), 1)
|
||||
return err
|
||||
}
|
||||
|
||||
if status {
|
||||
for {
|
||||
sent, err := p.device.Write([]byte(out))
|
||||
if err == nil {
|
||||
break
|
||||
} else {
|
||||
// log.Errorf("ERROR while sending serial command: %s\n", out)
|
||||
writeDebug(err.Error(), 2)
|
||||
out = out[sent:]
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// *** Helper functions for the CRC hostmode
|
||||
// Although these functions are small, I prefer to keep their functionality
|
||||
// separate. They follow the steps in the SCS documentation
|
||||
@@ -908,27 +858,86 @@ func (p *Modem) writeChannel(msg string, ch int, isCommand bool) error {
|
||||
|
||||
// read: Read from serial connection (thread safe)
|
||||
func (p *Modem) read(chunkSize int) (int, []byte, error) {
|
||||
p.mux.pactor.Lock()
|
||||
defer p.mux.pactor.Unlock()
|
||||
return p._read(chunkSize)
|
||||
}
|
||||
|
||||
// _read: Read from serial connection (NOT thread safe). To be used from read
|
||||
func (p *Modem) _read(chunkSize int) (int, []byte, error) {
|
||||
if err := p.checkSerialDevice(); err != nil {
|
||||
writeDebug(err.Error(), 1)
|
||||
return 0, []byte{}, err
|
||||
}
|
||||
|
||||
buf := make([]byte, chunkSize)
|
||||
if strings.HasPrefix(p.devicePath, "tcp://") {
|
||||
p.tcpdevice.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
|
||||
n, err := p.tcpdevice.Read(buf)
|
||||
if err != nil {
|
||||
writeDebug("Error received during read: "+err.Error(), 1)
|
||||
return 0, []byte{}, err
|
||||
}
|
||||
return n, buf[0:n], nil
|
||||
} else {
|
||||
if err := p.checkSerialDevice(); err != nil {
|
||||
writeDebug(err.Error(), 1)
|
||||
return 0, []byte{}, err
|
||||
}
|
||||
|
||||
p.mux.device.Lock()
|
||||
defer p.mux.device.Unlock()
|
||||
n, err := p.device.Read(buf)
|
||||
if err != nil {
|
||||
writeDebug("Error received during read: "+err.Error(), 1)
|
||||
return 0, []byte{}, err
|
||||
p.mux.device.Lock()
|
||||
defer p.mux.device.Unlock()
|
||||
n, err := p.device.Read(buf)
|
||||
if err != nil {
|
||||
writeDebug("Error received during read: "+err.Error(), 1)
|
||||
return 0, []byte{}, err
|
||||
}
|
||||
|
||||
return n, buf[0:n], nil
|
||||
}
|
||||
}
|
||||
|
||||
// Write to serial connection (thread safe)
|
||||
//
|
||||
// No other read/write operation allowed during this time
|
||||
func (p *Modem) write(cmd string) error {
|
||||
if strings.HasPrefix(p.devicePath, "tcp://") {
|
||||
|
||||
//TCP connection
|
||||
out := cmd + "\r"
|
||||
sent, err := p.tcpdevice.Write([]byte(out))
|
||||
if err == nil {
|
||||
return err
|
||||
} else {
|
||||
writeDebug(err.Error(), 2)
|
||||
out = out[sent:]
|
||||
return nil
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
//Serial connection
|
||||
if err := p.checkSerialDevice(); err != nil {
|
||||
writeDebug(err.Error(), 1)
|
||||
return err
|
||||
}
|
||||
|
||||
writeDebug("write: \n"+hex.Dump([]byte(cmd)), 3)
|
||||
|
||||
p.mux.device.Lock()
|
||||
defer p.mux.device.Unlock()
|
||||
out := cmd + "\r"
|
||||
for {
|
||||
|
||||
// check if the serial line is clear-to-send
|
||||
status, err := cts(p.device)
|
||||
if err != nil {
|
||||
writeDebug("GetModemStatusBits failed. cmd: "+cmd+" Error: "+err.Error(), 1)
|
||||
return err
|
||||
}
|
||||
|
||||
if status {
|
||||
for {
|
||||
sent, err := p.device.Write([]byte(out))
|
||||
if err == nil {
|
||||
break
|
||||
} else {
|
||||
writeDebug(err.Error(), 2)
|
||||
out = out[sent:]
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return n, buf[0:n], nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user