2024-07-21 13:05:09 +00:00
|
|
|
package at
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2024-07-25 13:58:09 +00:00
|
|
|
"io"
|
2024-07-21 13:05:09 +00:00
|
|
|
"log"
|
2024-07-31 19:18:44 +00:00
|
|
|
"sync"
|
2024-07-21 13:05:09 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"go.bug.st/serial"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Some constants
|
|
|
|
const (
|
|
|
|
ReadTimeout = time.Second
|
|
|
|
InputBufSize = 128
|
|
|
|
)
|
|
|
|
|
|
|
|
type atPort struct {
|
2024-07-23 16:02:28 +00:00
|
|
|
logger *log.Logger
|
|
|
|
|
2024-07-31 19:18:44 +00:00
|
|
|
mutex sync.Mutex // Mutex for all operation with serial port
|
|
|
|
|
2024-07-21 13:05:09 +00:00
|
|
|
baudrate int
|
|
|
|
portName string
|
|
|
|
port serial.Port
|
|
|
|
inputBuf []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
type Port interface {
|
2024-07-23 09:22:53 +00:00
|
|
|
GetName() string
|
2024-07-27 13:01:27 +00:00
|
|
|
GetBaudrate() int
|
2024-07-31 19:18:44 +00:00
|
|
|
SerialPort() serial.Port // For extra need
|
|
|
|
Mutex() sync.Locker // retruns pointer to mutex for advanced use like readign NMEA reports
|
2024-07-23 09:22:53 +00:00
|
|
|
|
2024-07-21 13:05:09 +00:00
|
|
|
Connect() error
|
|
|
|
Disconnect() error
|
|
|
|
IsConnected() bool
|
2024-07-23 09:22:53 +00:00
|
|
|
|
2024-07-29 15:53:55 +00:00
|
|
|
RawSend(msg string) (string, error)
|
2024-07-23 09:22:53 +00:00
|
|
|
Send(cmd string) (Resp, error)
|
2024-07-25 13:58:09 +00:00
|
|
|
|
|
|
|
io.Closer
|
2024-07-21 13:05:09 +00:00
|
|
|
}
|
|
|
|
|
2024-07-23 16:02:28 +00:00
|
|
|
func New(logger *log.Logger, portName string, baudrate int) Port {
|
2024-07-21 13:05:09 +00:00
|
|
|
return &atPort{
|
2024-07-23 16:02:28 +00:00
|
|
|
logger: logger,
|
2024-07-21 13:05:09 +00:00
|
|
|
portName: portName,
|
|
|
|
baudrate: baudrate,
|
|
|
|
inputBuf: make([]byte, InputBufSize),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-23 09:22:53 +00:00
|
|
|
func (p *atPort) GetName() string {
|
|
|
|
return p.portName
|
|
|
|
}
|
|
|
|
|
2024-07-27 13:01:27 +00:00
|
|
|
func (p *atPort) GetBaudrate() int {
|
|
|
|
return p.baudrate
|
|
|
|
}
|
|
|
|
|
2024-07-31 19:18:44 +00:00
|
|
|
func (p *atPort) SerialPort() serial.Port {
|
2024-07-23 09:22:53 +00:00
|
|
|
return p.port
|
|
|
|
}
|
|
|
|
|
2024-07-31 19:18:44 +00:00
|
|
|
func (p *atPort) Mutex() sync.Locker {
|
|
|
|
return &p.mutex
|
|
|
|
}
|
|
|
|
|
2024-07-21 13:05:09 +00:00
|
|
|
func (p *atPort) Connect() error {
|
2024-07-31 19:18:44 +00:00
|
|
|
p.mutex.Lock()
|
|
|
|
defer p.mutex.Unlock()
|
|
|
|
|
2024-07-23 16:02:28 +00:00
|
|
|
p.logger.Println("Connecting to", p.portName, "...")
|
2024-07-21 13:05:09 +00:00
|
|
|
s, err := serial.Open(p.portName, &serial.Mode{BaudRate: p.baudrate})
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("open port: %w", err)
|
|
|
|
}
|
|
|
|
// s.Close() There is no open f
|
|
|
|
// s.Open()
|
|
|
|
p.port = s
|
|
|
|
p.port.SetReadTimeout(ReadTimeout)
|
|
|
|
p.port.ResetInputBuffer()
|
|
|
|
p.port.ResetOutputBuffer()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *atPort) Disconnect() error {
|
2024-07-31 19:18:44 +00:00
|
|
|
p.mutex.Lock()
|
2024-07-21 13:05:09 +00:00
|
|
|
defer func() {
|
|
|
|
p.port = nil
|
2024-07-31 19:18:44 +00:00
|
|
|
p.mutex.Unlock()
|
2024-07-21 13:05:09 +00:00
|
|
|
}()
|
|
|
|
if err := p.port.Close(); err != nil {
|
|
|
|
return fmt.Errorf("close port: %w", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-07-23 09:22:53 +00:00
|
|
|
func (p *atPort) IsConnected() bool {
|
2024-07-31 19:18:44 +00:00
|
|
|
p.mutex.Lock()
|
|
|
|
defer p.mutex.Unlock()
|
|
|
|
|
2024-07-23 09:22:53 +00:00
|
|
|
return p.port != nil
|
|
|
|
}
|
|
|
|
|
2024-07-21 13:05:09 +00:00
|
|
|
// Low level write/read function
|
2024-07-29 15:53:55 +00:00
|
|
|
func (p *atPort) RawSend(msg string) (string, error) {
|
2024-07-31 19:18:44 +00:00
|
|
|
p.mutex.Lock()
|
|
|
|
defer p.mutex.Unlock()
|
|
|
|
|
2024-07-21 13:05:09 +00:00
|
|
|
// Write
|
2024-07-22 17:24:30 +00:00
|
|
|
if _, err := p.port.Write([]byte(msg)); err != nil {
|
2024-07-21 13:05:09 +00:00
|
|
|
return "", fmt.Errorf("serial port write: %w", err)
|
|
|
|
}
|
2024-07-31 19:18:44 +00:00
|
|
|
// time.Sleep(time.Millisecond)
|
2024-07-21 13:05:09 +00:00
|
|
|
// Read
|
|
|
|
readLen, err := p.port.Read(p.inputBuf)
|
2024-07-23 19:04:15 +00:00
|
|
|
// p.logger.Println(msg, "\x1b[38;2;150;150;150mRAWREAD:", string(p.inputBuf[:readLen]), "\x1b[38;2;255;255;255m")
|
2024-07-21 13:05:09 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("port read: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(p.inputBuf[:readLen]), nil
|
|
|
|
}
|
|
|
|
|
2024-07-23 09:22:53 +00:00
|
|
|
func (p *atPort) Send(cmd string) (Resp, error) {
|
|
|
|
cmd += "\r\n"
|
2024-07-29 15:53:55 +00:00
|
|
|
rawResp, err := p.RawSend(cmd)
|
2024-07-21 13:05:09 +00:00
|
|
|
if err != nil {
|
2024-07-23 09:22:53 +00:00
|
|
|
return RespNil, fmt.Errorf("make request: %w", err)
|
2024-07-21 13:05:09 +00:00
|
|
|
}
|
2024-07-23 09:22:53 +00:00
|
|
|
if len(rawResp) <= 4 {
|
2024-07-29 15:53:55 +00:00
|
|
|
return RespNil, fmt.Errorf("read too small msg: %d byte - %s", len(rawResp), string(rawResp))
|
2024-07-21 13:05:09 +00:00
|
|
|
}
|
2024-07-22 17:57:36 +00:00
|
|
|
resp := rawResp[2 : len(rawResp)-2] // Cut \r\n
|
2024-07-21 13:05:09 +00:00
|
|
|
|
2024-07-23 09:22:53 +00:00
|
|
|
return Resp(resp), nil
|
2024-07-21 13:05:09 +00:00
|
|
|
}
|
2024-07-25 13:58:09 +00:00
|
|
|
|
|
|
|
func (p *atPort) Close() error {
|
2024-07-31 19:18:44 +00:00
|
|
|
p.mutex.Lock()
|
|
|
|
defer p.mutex.Unlock()
|
|
|
|
|
2024-07-25 13:58:09 +00:00
|
|
|
return p.port.Close()
|
|
|
|
}
|