Potencially working.
This commit is contained in:
parent
c8f30c0caf
commit
f160282fe2
2
Makefile
2
Makefile
@ -5,7 +5,7 @@ build:
|
||||
# @./out/annalist.exe
|
||||
|
||||
linux:
|
||||
@$Env:GOOS="linux" $Env:GOARCH="arm" $Env:GOARM=5
|
||||
@$Env:GOOS="linux"; $Env:GOARCH="arm"; $Env:GOARM=5
|
||||
|
||||
# .profile
|
||||
# cgo_enabled 0
|
@ -1,53 +0,0 @@
|
||||
package modem
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"go.bug.st/serial"
|
||||
)
|
||||
|
||||
func (m *modem) makeAtReq(msg string) (string, error) {
|
||||
log.Println("Write...")
|
||||
if _, err := m.serialPort.Write([]byte(msg)); err != nil {
|
||||
return "", fmt.Errorf("serial port write: %w", err)
|
||||
}
|
||||
log.Println("Read...")
|
||||
readLen, err := m.serialPort.Read(m.inputBuf)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("port read: %w", err)
|
||||
}
|
||||
return strings.Split(string(m.inputBuf[:readLen]), "\n")[1], nil
|
||||
}
|
||||
|
||||
func (m *modem) makeAtEchoReqAndCheck(msg, checkMsg string) (bool, error) {
|
||||
ans, err := m.makeAtReq(msg)
|
||||
log.Println(msg, checkMsg)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return (len(ans) >= len(checkMsg) && ans[:len(checkMsg)] == checkMsg), nil
|
||||
}
|
||||
|
||||
func (m *modem) connect(port string) error {
|
||||
log.Println("Connecting to", port, "...")
|
||||
s, err := serial.Open(port, &serial.Mode{BaudRate: m.baudrate})
|
||||
if err != nil {
|
||||
return fmt.Errorf("open port: %w", err)
|
||||
}
|
||||
// s.Close() There is no open f
|
||||
// s.Open()
|
||||
m.serialPort = s
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *modem) disconnect() error {
|
||||
defer func() {
|
||||
m.serialPort = nil
|
||||
}()
|
||||
if err := m.serialPort.Close(); err != nil {
|
||||
return fmt.Errorf("close port: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
154
api/modem/at/at.go
Normal file
154
api/modem/at/at.go
Normal file
@ -0,0 +1,154 @@
|
||||
package at
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.bug.st/serial"
|
||||
)
|
||||
|
||||
// Some constants
|
||||
const (
|
||||
ReadTimeout = time.Second
|
||||
InputBufSize = 128
|
||||
)
|
||||
|
||||
// Command types
|
||||
type CmdType byte
|
||||
|
||||
// Command types base on request/answer semantic:
|
||||
const (
|
||||
CmdTest CmdType = iota
|
||||
// AT\r\n
|
||||
// OK
|
||||
CmdCheck
|
||||
// AT+<CMD>\r\n
|
||||
// OK
|
||||
CmdGet
|
||||
// AT+<CMD>\r\n
|
||||
// +<CMD>: <ANS>
|
||||
CmdQuestion
|
||||
// AT+<CMD>?\r\n
|
||||
// +<CMD>: <ANS>
|
||||
)
|
||||
|
||||
type atPort struct {
|
||||
baudrate int
|
||||
portName string
|
||||
port serial.Port
|
||||
inputBuf []byte
|
||||
}
|
||||
|
||||
type Port interface {
|
||||
Connect() error
|
||||
Disconnect() error
|
||||
Request(cmdType CmdType, cmd string) (string, error)
|
||||
GetName() string
|
||||
IsConnected() bool
|
||||
GetSerialPort() serial.Port // For extra need
|
||||
}
|
||||
|
||||
func New(portName string, baudrate int) Port {
|
||||
return &atPort{
|
||||
portName: portName,
|
||||
baudrate: baudrate,
|
||||
inputBuf: make([]byte, InputBufSize),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *atPort) Connect() error {
|
||||
log.Println("Connecting to", p.portName, "...")
|
||||
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 {
|
||||
defer func() {
|
||||
p.port = nil
|
||||
}()
|
||||
if err := p.port.Close(); err != nil {
|
||||
return fmt.Errorf("close port: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Low level write/read function
|
||||
func (p *atPort) makeReq(msg string) (string, error) {
|
||||
// Write
|
||||
p.port.ResetInputBuffer()
|
||||
log.Println("Write...") // DEBUG
|
||||
if written, err := p.port.Write([]byte(msg)); err != nil {
|
||||
return "", fmt.Errorf("serial port write: %w", err)
|
||||
} else {
|
||||
log.Println("Written:", written) // DEBUG
|
||||
}
|
||||
// Read
|
||||
log.Println("Read...") // DEBUG
|
||||
readLen, err := p.port.Read(p.inputBuf)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("port read: %w", err)
|
||||
}
|
||||
|
||||
log.Println("Read: ", readLen, string(p.inputBuf[:readLen])) // DEBUG
|
||||
return string(p.inputBuf[:readLen]), nil
|
||||
}
|
||||
|
||||
func (p *atPort) Request(cmdType CmdType, cmd string) (string, error) {
|
||||
msg := "AT"
|
||||
// Make command
|
||||
// By default it just will be AT check cmd
|
||||
switch cmdType {
|
||||
case CmdGet, CmdCheck:
|
||||
msg += cmd
|
||||
case CmdQuestion:
|
||||
msg += cmd + "?"
|
||||
}
|
||||
msg += "\r\n"
|
||||
rawResp, err := p.makeReq(msg)
|
||||
log.Println("Got")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("make at request: %w", err)
|
||||
}
|
||||
if len(rawResp) == 0 {
|
||||
return "", fmt.Errorf("read nothing")
|
||||
}
|
||||
resp := strings.Split(rawResp, "\n")
|
||||
switch cmdType {
|
||||
case CmdTest, CmdCheck:
|
||||
// Check and test cmds do not suppose anything but OK
|
||||
if len(resp[1]) >= 2 && resp[1][:2] == "OK" {
|
||||
return "", nil
|
||||
}
|
||||
return "", fmt.Errorf("connection lost")
|
||||
case CmdGet, CmdQuestion:
|
||||
checkL := len(cmd) + 1
|
||||
if len(resp[1]) >= checkL && resp[1][:checkL] != "+"+cmd {
|
||||
return "", fmt.Errorf("connetion lost")
|
||||
}
|
||||
return strings.Split(resp[1], ":")[1], nil
|
||||
}
|
||||
return "", fmt.Errorf("undefined command type")
|
||||
}
|
||||
|
||||
func (p *atPort) GetName() string {
|
||||
return p.portName
|
||||
}
|
||||
|
||||
func (p *atPort) IsConnected() bool {
|
||||
return p.port != nil
|
||||
}
|
||||
|
||||
func (p *atPort) GetSerialPort() serial.Port {
|
||||
return p.port
|
||||
}
|
@ -1,44 +1,44 @@
|
||||
package modem
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
gpio "github.com/warthog618/go-gpiocdev"
|
||||
gpio "github.com/stianeikeland/go-rpio/v4"
|
||||
)
|
||||
|
||||
func (m *modem) PowerOn() error {
|
||||
c, err := gpio.NewChip(m.deviceName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("gpio new chip: %w", err)
|
||||
}
|
||||
l, err := c.RequestLine(m.powerKey, gpio.AsOutput(0))
|
||||
if err != nil {
|
||||
return fmt.Errorf("gpio request line: %w", err)
|
||||
}
|
||||
m.gpioLine = l
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
if err := m.gpioLine.SetValue(1); err != nil {
|
||||
return fmt.Errorf("gpio set value: %w", err)
|
||||
}
|
||||
time.Sleep(3 * time.Second)
|
||||
if err := m.gpioLine.SetValue(0); err != nil {
|
||||
return fmt.Errorf("gpio set value: %w", err)
|
||||
}
|
||||
time.Sleep(30 * time.Second)
|
||||
return nil
|
||||
type gpioPin struct {
|
||||
Pin gpio.Pin
|
||||
}
|
||||
|
||||
func (m *modem) PowerOff() error {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
if err := m.gpioLine.SetValue(1); err != nil {
|
||||
return fmt.Errorf("gpio set value: %w", err)
|
||||
}
|
||||
time.Sleep(3 * time.Second)
|
||||
if err := m.gpioLine.SetValue(0); err != nil {
|
||||
return fmt.Errorf("gpio set value: %w", err)
|
||||
}
|
||||
time.Sleep(30 * time.Second)
|
||||
m.gpioLine = nil
|
||||
return nil
|
||||
func (p gpioPin) Init() error {
|
||||
return gpio.Open()
|
||||
}
|
||||
|
||||
func (p gpioPin) sendOnOffSignal() {
|
||||
p.Pin.Output()
|
||||
log.Println("Power on 0/3 + 100ms")
|
||||
p.Pin.Low()
|
||||
p.Pin.Toggle()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
log.Println("Power on 1/3 + 3s")
|
||||
p.Pin.High()
|
||||
p.Pin.Toggle()
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
log.Println("Power on 2/3 + 30s")
|
||||
p.Pin.Low()
|
||||
p.Pin.Toggle()
|
||||
time.Sleep(30 * time.Second)
|
||||
|
||||
log.Println("Power on 3/3")
|
||||
}
|
||||
|
||||
func (p gpioPin) PowerOn() {
|
||||
p.sendOnOffSignal()
|
||||
}
|
||||
|
||||
func (p *gpioPin) PowerOff() {
|
||||
p.sendOnOffSignal()
|
||||
}
|
||||
|
@ -1,194 +1,199 @@
|
||||
package modem
|
||||
|
||||
import (
|
||||
"annalist/api/modem/at"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"os/exec"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
gpio "github.com/warthog618/go-gpiocdev"
|
||||
"go.bug.st/serial"
|
||||
)
|
||||
|
||||
type GpsInfo struct {
|
||||
Latitude float64 `json:"Latitude"`
|
||||
Longitude float64 `json:"Longitude"`
|
||||
LatitudeIndicator string `json:"Latitude_indicator"` // North/South
|
||||
LongitudeIndicator string `json:"Longitude_indicator"` // West/East
|
||||
Speed float64 `json:"Speed"`
|
||||
Course float64 `json:"-"`
|
||||
Altitude float64 `json:"-"`
|
||||
Date string `json:"-"`
|
||||
Time string `json:"-"`
|
||||
}
|
||||
|
||||
type modem struct {
|
||||
// Serial stuff
|
||||
port string
|
||||
deviceName string
|
||||
baudrate int
|
||||
inputBuf []byte
|
||||
serialPort serial.Port
|
||||
|
||||
deviceName string
|
||||
port at.Port
|
||||
isAvailable bool
|
||||
|
||||
// Gpio stuff
|
||||
powerKey int
|
||||
gpioLine *gpio.Line
|
||||
onOffPin gpioPin
|
||||
|
||||
// Other values
|
||||
speed float64
|
||||
latitude_ns float64
|
||||
latitude float64
|
||||
longitude_we float64
|
||||
longitude float64
|
||||
|
||||
gpsInfo GpsInfo
|
||||
lastUpdateTime time.Time
|
||||
}
|
||||
|
||||
type Modem interface {
|
||||
Init() error
|
||||
SearchPort(isSoft bool) error
|
||||
PowerOn() error
|
||||
PowerOff() error
|
||||
Connect() error
|
||||
Ping() (bool, error)
|
||||
Ping() error
|
||||
SwitchToGpsMode() error
|
||||
CalculateSpeed(newLatitude, newlongitude float64)
|
||||
Update() error
|
||||
GetInfo() string
|
||||
GetInfo() (string, error)
|
||||
TestGPS() error
|
||||
}
|
||||
|
||||
func New() Modem {
|
||||
return &modem{
|
||||
baudrate: 115200,
|
||||
powerKey: 6,
|
||||
onOffPin: gpioPin{Pin: 6},
|
||||
lastUpdateTime: time.Now(),
|
||||
inputBuf: make([]byte, 128),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *modem) Init() error {
|
||||
// Turn module on
|
||||
if err := m.onOffPin.Init(); err != nil {
|
||||
return fmt.Errorf("gpio pin init: %w", err)
|
||||
}
|
||||
m.onOffPin.PowerOn()
|
||||
|
||||
// Soft search
|
||||
if err := m.SearchPort(true); err != nil {
|
||||
return fmt.Errorf("soft port search: %w", err)
|
||||
}
|
||||
if m.port == "" {
|
||||
|
||||
return nil
|
||||
|
||||
// Common search
|
||||
if m.port == nil {
|
||||
if err := m.SearchPort(false); err != nil {
|
||||
return fmt.Errorf("not soft port search: %w", err)
|
||||
}
|
||||
}
|
||||
if m.port == "" {
|
||||
if m.port == nil {
|
||||
return errors.New("no port is detected")
|
||||
}
|
||||
|
||||
// Connect
|
||||
if err := m.Connect(); err != nil {
|
||||
return fmt.Errorf("connect: %w", err)
|
||||
}
|
||||
// Tests
|
||||
if err := m.TestGPS(); err != nil {
|
||||
return fmt.Errorf("testGPS: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *modem) SearchPort(isSoft bool) error {
|
||||
ports := []string{}
|
||||
func (m *modem) checkPort(portName string) error {
|
||||
// Check device for existance
|
||||
if _, err := os.Stat(portName); err != nil {
|
||||
return fmt.Errorf("device does not exist")
|
||||
}
|
||||
|
||||
// Get ports
|
||||
if isSoft {
|
||||
ports = []string{"ttyUSB1", "ttyUSB2", "ttyUSB3"}
|
||||
} else {
|
||||
/**/
|
||||
log.Print("Search for ports...")
|
||||
out, err := exec.Command("/bin/ls", "/dev").Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("execute ls command: %w", err)
|
||||
}
|
||||
allPorts := strings.Split(string(out), "\n")
|
||||
for _, p := range allPorts {
|
||||
if len(p) > 2 && p[:3] == "tty" {
|
||||
ports = append(ports, p)
|
||||
}
|
||||
}
|
||||
// slices.Reverse(ports) // TODO why
|
||||
}
|
||||
// Check ports
|
||||
log.Println("Found ports: ", ports)
|
||||
log.Println("Check...")
|
||||
defer func() {
|
||||
if m.serialPort != nil {
|
||||
m.disconnect() // TODO maybe handle
|
||||
}
|
||||
}()
|
||||
for _, p := range ports {
|
||||
if m.serialPort != nil {
|
||||
if err := m.disconnect(); err != nil {
|
||||
return fmt.Errorf("disconnect: %w", err)
|
||||
}
|
||||
}
|
||||
log.Println("Checking port: ", p)
|
||||
if _, err := os.Stat("/dev/" + p); err != nil {
|
||||
continue
|
||||
}
|
||||
if err := m.connect("/dev/" + p); err != nil {
|
||||
log.Println("Error:", fmt.Errorf("connect: %w", err).Error())
|
||||
continue
|
||||
// Check serial connection
|
||||
// Connect
|
||||
port := at.New(portName, m.baudrate)
|
||||
if err := port.Connect(); err != nil {
|
||||
return fmt.Errorf("connect: %w", err)
|
||||
}
|
||||
defer port.Disconnect() // Do not bother about errors...
|
||||
|
||||
// Ping
|
||||
log.Println("Ping...")
|
||||
if ok, err := m.Ping(); err != nil || !ok {
|
||||
if err != nil {
|
||||
|
||||
if err := m.Ping(); err != nil {
|
||||
return fmt.Errorf("ping error: %w", err)
|
||||
}
|
||||
return errors.New("modem does not ping")
|
||||
}
|
||||
|
||||
// Check model
|
||||
{
|
||||
ok, err := m.makeAtEchoReqAndCheck("AT+CGMM\r\n", "SIMCOM_SIM7600E-H")
|
||||
model, err := port.Request(at.CmdGet, "CGMM")
|
||||
if err != nil {
|
||||
return fmt.Errorf("make serial request: %w", err)
|
||||
return fmt.Errorf("get model: %w", err)
|
||||
}
|
||||
if !ok {
|
||||
continue
|
||||
if model != "SIMCOM_SIM7600E-H" {
|
||||
return fmt.Errorf("invalid modem model: %s", model)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *modem) SearchPort(isSoft bool) error {
|
||||
// Get ports
|
||||
ports := []string{"ttyUSB1", "ttyUSB2", "ttyUSB3"}
|
||||
if !isSoft {
|
||||
ps, err := GetTtyDevices()
|
||||
if err != nil {
|
||||
fmt.Errorf("get serial devices: %w", err)
|
||||
}
|
||||
ports = ps
|
||||
}
|
||||
|
||||
// Check ports
|
||||
SearchLoop:
|
||||
for _, p := range ports {
|
||||
log.Printf("Checking port %s ...\n", p)
|
||||
|
||||
if err := m.checkPort("/dev/" + p); err != nil {
|
||||
log.Printf("Check failed: %s\n", err.Error())
|
||||
continue SearchLoop
|
||||
}
|
||||
|
||||
log.Print("Found modem on port: ", p)
|
||||
m.port = "/dev/" + p
|
||||
m.port = at.New("/dev/"+p, m.baudrate)
|
||||
m.isAvailable = true
|
||||
return nil
|
||||
}
|
||||
// return errors.New("no a compatible modem port found")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *modem) Connect() error {
|
||||
return m.connect(m.port)
|
||||
if m.port == nil {
|
||||
return fmt.Errorf("port is not defined")
|
||||
}
|
||||
return m.port.Connect()
|
||||
}
|
||||
|
||||
func (m *modem) Ping() (bool, error) {
|
||||
return m.makeAtEchoReqAndCheck("AT\r\n", "OK")
|
||||
func (m *modem) Ping() error {
|
||||
_, err := m.port.Request(at.CmdTest, "")
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *modem) SwitchToGpsMode() error {
|
||||
if err := m.serialPort.ResetInputBuffer(); err != nil {
|
||||
log.Println("Enabling GPS mode...")
|
||||
// Reset intput
|
||||
if err := m.port.GetSerialPort().ResetInputBuffer(); err != nil {
|
||||
return fmt.Errorf("reset input buffer: %w", err)
|
||||
}
|
||||
ans, err := m.makeAtReq("AT+CGPS?\r\n")
|
||||
|
||||
// Check gps mode status
|
||||
ans, err := m.port.Request(at.CmdQuestion, "CGPS")
|
||||
if err != nil {
|
||||
return fmt.Errorf("make serial request: %w", err)
|
||||
return fmt.Errorf("make at ask: %w", err)
|
||||
}
|
||||
resp := strings.Split(ans, ":")
|
||||
if !(len(resp) > 1 && resp[0] == "+CGPS") {
|
||||
return errors.New("lost connection while checking gps status")
|
||||
}
|
||||
switch resp[1][1] {
|
||||
case '1':
|
||||
if ans == "1" {
|
||||
log.Println("GPS already enabled")
|
||||
return nil
|
||||
case '0':
|
||||
ok, err := m.makeAtEchoReqAndCheck("AT+CGPS=1", "OK")
|
||||
}
|
||||
|
||||
// Modem is not in GPS mode
|
||||
_, err = m.port.Request(at.CmdCheck, "CGPS=1")
|
||||
if err != nil {
|
||||
return fmt.Errorf("try to switch to gps mode echo reqest: %w", err)
|
||||
}
|
||||
if !ok {
|
||||
return errors.New("lost connection while trying to switch to gps mode")
|
||||
}
|
||||
default:
|
||||
return errors.New("unexpected response of gps status")
|
||||
return fmt.Errorf("try to switch to gps: %w", err)
|
||||
}
|
||||
log.Println("GPS mode enabled")
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -199,13 +204,13 @@ func deg2rad(deg float64) float64 {
|
||||
func (m *modem) CalculateSpeed(newLatitude, newLongitude float64) {
|
||||
log.Println("Calculate speed")
|
||||
earthRad := 6371.0 // TODO ?
|
||||
dLat := deg2rad(math.Abs(newLatitude - m.latitude))
|
||||
dLon := deg2rad(math.Abs(newLongitude - m.longitude))
|
||||
dLat := deg2rad(math.Abs(newLatitude - m.gpsInfo.Latitude))
|
||||
dLon := deg2rad(math.Abs(newLongitude - m.gpsInfo.Longitude))
|
||||
a := math.Sin(dLat/2)*math.Sin(dLat/2) +
|
||||
math.Cos(deg2rad(newLatitude))*math.Cos(deg2rad(m.latitude))*math.Sin(dLon/2)*math.Sin(dLon/2)
|
||||
math.Cos(deg2rad(newLatitude))*math.Cos(deg2rad(m.gpsInfo.Latitude))*math.Sin(dLon/2)*math.Sin(dLon/2)
|
||||
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
|
||||
|
||||
m.speed = earthRad * c / (math.Abs(float64(time.Since(m.lastUpdateTime))))
|
||||
m.gpsInfo.Speed = earthRad * c / (math.Abs(float64(time.Since(m.lastUpdateTime))))
|
||||
}
|
||||
|
||||
func (m *modem) Update() error {
|
||||
@ -214,23 +219,143 @@ func (m *modem) Update() error {
|
||||
log.Println("No connection to module")
|
||||
return nil
|
||||
}
|
||||
m.serialPort.ResetInputBuffer()
|
||||
// MAKE
|
||||
ans, err := m.port.Request(at.CmdQuestion, "CGPSINFO")
|
||||
if err != nil {
|
||||
return fmt.Errorf("check GPS info mode: %w", err)
|
||||
}
|
||||
ok := ans == "1"
|
||||
if !ok {
|
||||
_, err := m.port.Request(at.CmdCheck, "CGPSINFO")
|
||||
if err != nil {
|
||||
return fmt.Errorf("switch to GPS info mode: %w", err)
|
||||
}
|
||||
log.Println("switched to GPS mode")
|
||||
} else {
|
||||
log.Println("mode in right GPS mode")
|
||||
}
|
||||
|
||||
// Update
|
||||
|
||||
log.Println("Receiving GPS data...")
|
||||
resp, err := m.port.Request(at.CmdGet, "GPSINFO")
|
||||
if err != nil {
|
||||
return fmt.Errorf("receive GPS data: %w", err)
|
||||
}
|
||||
|
||||
log.Println("Decoding data...")
|
||||
coordinates := strings.Split(resp, ",")
|
||||
|
||||
m.gpsInfo.Latitude, err = strconv.ParseFloat(coordinates[0], 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse latitude: %w", err)
|
||||
}
|
||||
m.gpsInfo.Longitude, err = strconv.ParseFloat(coordinates[2], 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse longitude: %w", err)
|
||||
}
|
||||
m.gpsInfo.LatitudeIndicator = coordinates[1]
|
||||
m.gpsInfo.LatitudeIndicator = coordinates[3]
|
||||
m.gpsInfo.Date = coordinates[4]
|
||||
m.gpsInfo.Time = coordinates[5]
|
||||
m.gpsInfo.Altitude, err = strconv.ParseFloat(coordinates[6], 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse altitude: %w", err)
|
||||
}
|
||||
m.gpsInfo.Speed, err = strconv.ParseFloat(coordinates[7], 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse speed: %w", err)
|
||||
}
|
||||
m.gpsInfo.Course, err = strconv.ParseFloat(coordinates[8], 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse course: %w", err)
|
||||
}
|
||||
log.Println("Decoded successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *modem) GetInfo() string {
|
||||
return ""
|
||||
type ModemInfo struct {
|
||||
Port string `json:"Port"`
|
||||
GpsInfo
|
||||
}
|
||||
|
||||
type Info struct {
|
||||
Modem ModemInfo `json:"Modem"`
|
||||
}
|
||||
|
||||
func (m *modem) GetInfo() (string, error) {
|
||||
info := Info{
|
||||
Modem: ModemInfo{
|
||||
Port: m.port.GetName(),
|
||||
GpsInfo: m.gpsInfo,
|
||||
},
|
||||
}
|
||||
buf, err := json.Marshal(info)
|
||||
if err != nil {
|
||||
fmt.Errorf("marshal info: %w", err)
|
||||
}
|
||||
return string(buf), nil // why you clamp
|
||||
}
|
||||
|
||||
// Difference: I do not set \n at the end of string
|
||||
func (m *modem) GetShortInfo() string {
|
||||
return fmt.Sprintf("%f,%s,%f,%s", m.gpsInfo.Latitude, m.gpsInfo.LatitudeIndicator, m.gpsInfo.Longitude, m.gpsInfo.LongitudeIndicator)
|
||||
}
|
||||
|
||||
func (m *modem) SaveGPS(path string) error {
|
||||
f, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open file: %w", err)
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
if _, err = f.WriteString(m.GetShortInfo()); err != nil {
|
||||
return fmt.Errorf("write file: %W", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *modem) TestGPS() error {
|
||||
log.Println("Testing GPS")
|
||||
|
||||
if err := m.SwitchToGpsMode(); err != nil {
|
||||
return fmt.Errorf("switch to GPS: %w", err)
|
||||
}
|
||||
|
||||
if err := m.Update(); err != nil {
|
||||
return fmt.Errorf("update: %w", err)
|
||||
}
|
||||
|
||||
log.Println("Current coords:", m.GetShortInfo())
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetTtyDevices() ([]string, error) {
|
||||
devices := []string{}
|
||||
|
||||
// Get ports
|
||||
/**/
|
||||
log.Print("Search for ports...")
|
||||
out, err := exec.Command("/bin/ls", "/dev").Output()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("execute ls command: %w", err)
|
||||
}
|
||||
allPorts := strings.Split(string(out), "\n")
|
||||
for _, p := range allPorts {
|
||||
if len(p) > 3 && p[:3] == "tty" {
|
||||
devices = append(devices, p)
|
||||
}
|
||||
}
|
||||
slices.Reverse(devices) // ASK why
|
||||
|
||||
return devices, nil
|
||||
}
|
||||
|
||||
/*
|
||||
TODOs:
|
||||
maybe to store read/write buf in obj
|
||||
QUESTIONS:
|
||||
do many threads?
|
||||
JSON why you clamp
|
||||
*/
|
||||
|
||||
/*
|
||||
|
3
go.mod
3
go.mod
@ -3,11 +3,12 @@ module annalist
|
||||
go 1.22.5
|
||||
|
||||
require (
|
||||
github.com/warthog618/go-gpiocdev v0.9.0
|
||||
github.com/stianeikeland/go-rpio/v4 v4.6.0
|
||||
go.bug.st/serial v1.6.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/creack/goselect v0.1.2 // indirect
|
||||
github.com/stretchr/testify v1.9.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
)
|
||||
|
8
go.sum
8
go.sum
@ -2,16 +2,12 @@ github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0
|
||||
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stianeikeland/go-rpio/v4 v4.6.0 h1:eAJgtw3jTtvn/CqwbC82ntcS+dtzUTgo5qlZKe677EY=
|
||||
github.com/stianeikeland/go-rpio/v4 v4.6.0/go.mod h1:A3GvHxC1Om5zaId+HqB3HKqx4K/AqeckxB7qRjxMK7o=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/warthog618/go-gpiocdev v0.9.0 h1:AZWUq1WObgKCO9cJCACFpwWQw6yu8vJbIE6fRZ+6cbY=
|
||||
github.com/warthog618/go-gpiocdev v0.9.0/go.mod h1:GV4NZC82fWJERqk7Gu0+KfLSDIBEDNm6aPGiHlmT5fY=
|
||||
github.com/warthog618/go-gpiosim v0.1.0 h1:2rTMTcKUVZxpUuvRKsagnKAbKpd3Bwffp87xywEDVGI=
|
||||
github.com/warthog618/go-gpiosim v0.1.0/go.mod h1:Ngx/LYI5toxHr4E+Vm6vTgCnt0of0tktsSuMUEJ2wCI=
|
||||
go.bug.st/serial v1.6.2 h1:kn9LRX3sdm+WxWKufMlIRndwGfPWsH1/9lCWXQCasq8=
|
||||
go.bug.st/serial v1.6.2/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
|
6
main.go
6
main.go
@ -16,4 +16,10 @@ func main() {
|
||||
func mainE() error {
|
||||
m := modem.New()
|
||||
return m.Init()
|
||||
// ports, err := serial.GetPortsList()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// log.Println(ports)
|
||||
// return nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user