sim-modem/api/modem/at/at.go

158 lines
3.0 KiB
Go
Raw Normal View History

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"
"sync"
2024-07-21 13:05:09 +00:00
"time"
"go.bug.st/serial"
)
// Some constants
const (
ReadTimeout = time.Second
2024-08-07 08:35:06 +00:00
InputBufSize = 512
2024-07-21 13:05:09 +00:00
)
type atPort struct {
2024-07-23 16:02:28 +00:00
logger *log.Logger
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
GetBaudrate() int
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
}
func (p *atPort) GetBaudrate() int {
return p.baudrate
}
func (p *atPort) SerialPort() serial.Port {
2024-07-23 09:22:53 +00:00
return p.port
}
func (p *atPort) Mutex() sync.Locker {
return &p.mutex
}
2024-07-21 13:05:09 +00:00
func (p *atPort) Connect() error {
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 {
p.mutex.Lock()
2024-07-21 13:05:09 +00:00
defer func() {
p.port = nil
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 {
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) {
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)
}
// time.Sleep(time.Millisecond)
2024-07-21 13:05:09 +00:00
// Read
2024-08-09 15:17:20 +00:00
outBuf := make([]byte, 0)
readLoop:
for {
readLen, err := p.port.Read(p.inputBuf)
if err != nil {
return "", fmt.Errorf("port read: %w", err)
}
if readLen == 0 {
break readLoop
}
outBuf = append(outBuf, p.inputBuf[:readLen]...)
if readLen < len(p.inputBuf) {
break readLoop
}
2024-07-21 13:05:09 +00:00
}
2024-08-09 15:17:20 +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
2024-08-09 15:17:20 +00:00
return string(outBuf), nil
2024-07-21 13:05:09 +00:00
}
2024-07-23 09:22:53 +00:00
func (p *atPort) Send(cmd string) (Resp, error) {
2024-08-09 15:17:20 +00:00
rawResp, err := p.RawSend(cmd + "\r\n")
2024-07-21 13:05:09 +00:00
if err != nil {
2024-08-09 15:17:20 +00:00
return RespNil, fmt.Errorf("%s request: %w", cmd, err)
2024-07-21 13:05:09 +00:00
}
2024-07-23 09:22:53 +00:00
if len(rawResp) <= 4 {
2024-08-09 15:17:20 +00:00
return RespNil, fmt.Errorf("%s request: read too small msg: %d byte - %s", cmd, 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 {
p.mutex.Lock()
defer p.mutex.Unlock()
2024-07-25 13:58:09 +00:00
return p.port.Close()
}