Initial.
This commit is contained in:
commit
c8f30c0caf
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
out/
|
||||
Makefile
|
||||
go.sum
|
||||
.git/
|
11
Makefile
Normal file
11
Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
build:
|
||||
@go build -o ./out/annalist.exe main.go
|
||||
#run: build
|
||||
# @./out/annalist.exe
|
||||
|
||||
linux:
|
||||
@$Env:GOOS="linux" $Env:GOARCH="arm" $Env:GOARM=5
|
||||
|
||||
# .profile
|
||||
# cgo_enabled 0
|
53
api/modem/at.go
Normal file
53
api/modem/at.go
Normal file
@ -0,0 +1,53 @@
|
||||
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
|
||||
}
|
44
api/modem/gpio.go
Normal file
44
api/modem/gpio.go
Normal file
@ -0,0 +1,44 @@
|
||||
package modem
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
gpio "github.com/warthog618/go-gpiocdev"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
237
api/modem/modem.go
Normal file
237
api/modem/modem.go
Normal file
@ -0,0 +1,237 @@
|
||||
package modem
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
gpio "github.com/warthog618/go-gpiocdev"
|
||||
"go.bug.st/serial"
|
||||
)
|
||||
|
||||
type modem struct {
|
||||
// Serial stuff
|
||||
port string
|
||||
deviceName string
|
||||
baudrate int
|
||||
inputBuf []byte
|
||||
serialPort serial.Port
|
||||
isAvailable bool
|
||||
|
||||
// Gpio stuff
|
||||
powerKey int
|
||||
gpioLine *gpio.Line
|
||||
|
||||
// Other values
|
||||
speed float64
|
||||
latitude_ns float64
|
||||
latitude float64
|
||||
longitude_we float64
|
||||
longitude float64
|
||||
|
||||
lastUpdateTime time.Time
|
||||
}
|
||||
|
||||
type Modem interface {
|
||||
Init() error
|
||||
SearchPort(isSoft bool) error
|
||||
PowerOn() error
|
||||
PowerOff() error
|
||||
Connect() error
|
||||
Ping() (bool, error)
|
||||
SwitchToGpsMode() error
|
||||
CalculateSpeed(newLatitude, newlongitude float64)
|
||||
Update() error
|
||||
GetInfo() string
|
||||
TestGPS() error
|
||||
}
|
||||
|
||||
func New() Modem {
|
||||
return &modem{
|
||||
baudrate: 115200,
|
||||
powerKey: 6,
|
||||
lastUpdateTime: time.Now(),
|
||||
inputBuf: make([]byte, 128),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *modem) Init() error {
|
||||
if err := m.SearchPort(true); err != nil {
|
||||
return fmt.Errorf("soft port search: %w", err)
|
||||
}
|
||||
if m.port == "" {
|
||||
if err := m.SearchPort(false); err != nil {
|
||||
return fmt.Errorf("not soft port search: %w", err)
|
||||
}
|
||||
}
|
||||
if m.port == "" {
|
||||
return errors.New("no port is detected")
|
||||
}
|
||||
if err := m.Connect(); err != nil {
|
||||
return fmt.Errorf("connect: %w", err)
|
||||
}
|
||||
if err := m.TestGPS(); err != nil {
|
||||
return fmt.Errorf("testGPS: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *modem) SearchPort(isSoft bool) error {
|
||||
ports := []string{}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// Ping
|
||||
log.Println("Ping...")
|
||||
if ok, err := m.Ping(); err != nil || !ok {
|
||||
if 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")
|
||||
if err != nil {
|
||||
return fmt.Errorf("make serial request: %w", err)
|
||||
}
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
log.Print("Found modem on port: ", p)
|
||||
m.port = "/dev/" + p
|
||||
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)
|
||||
}
|
||||
|
||||
func (m *modem) Ping() (bool, error) {
|
||||
return m.makeAtEchoReqAndCheck("AT\r\n", "OK")
|
||||
}
|
||||
|
||||
func (m *modem) SwitchToGpsMode() error {
|
||||
if err := m.serialPort.ResetInputBuffer(); err != nil {
|
||||
return fmt.Errorf("reset input buffer: %w", err)
|
||||
}
|
||||
ans, err := m.makeAtReq("AT+CGPS?\r\n")
|
||||
if err != nil {
|
||||
return fmt.Errorf("make serial request: %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':
|
||||
log.Println("GPS already enabled")
|
||||
return nil
|
||||
case '0':
|
||||
ok, err := m.makeAtEchoReqAndCheck("AT+CGPS=1", "OK")
|
||||
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 nil
|
||||
}
|
||||
|
||||
func deg2rad(deg float64) float64 {
|
||||
return deg * (math.Pi / 180)
|
||||
}
|
||||
|
||||
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))
|
||||
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)
|
||||
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
|
||||
|
||||
m.speed = earthRad * c / (math.Abs(float64(time.Since(m.lastUpdateTime))))
|
||||
}
|
||||
|
||||
func (m *modem) Update() error {
|
||||
log.Println("Update")
|
||||
if !m.isAvailable {
|
||||
log.Println("No connection to module")
|
||||
return nil
|
||||
}
|
||||
m.serialPort.ResetInputBuffer()
|
||||
// MAKE
|
||||
}
|
||||
|
||||
func (m *modem) GetInfo() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *modem) TestGPS() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
TODOs:
|
||||
maybe to store read/write buf in obj
|
||||
QUESTIONS:
|
||||
do many threads?
|
||||
*/
|
||||
|
||||
/*
|
||||
*/
|
13
go.mod
Normal file
13
go.mod
Normal file
@ -0,0 +1,13 @@
|
||||
module annalist
|
||||
|
||||
go 1.22.5
|
||||
|
||||
require (
|
||||
github.com/warthog618/go-gpiocdev v0.9.0
|
||||
go.bug.st/serial v1.6.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/creack/goselect v0.1.2 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
)
|
20
go.sum
Normal file
20
go.sum
Normal file
@ -0,0 +1,20 @@
|
||||
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/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=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
19
main.go
Normal file
19
main.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"annalist/api/modem"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Println("CGSG forever!!!")
|
||||
if err := mainE(); err != nil {
|
||||
log.Println("MAIN finished with error:", err.Error())
|
||||
}
|
||||
log.Println("END")
|
||||
}
|
||||
|
||||
func mainE() error {
|
||||
m := modem.New()
|
||||
return m.Init()
|
||||
}
|
Loading…
Reference in New Issue
Block a user