Added service checks. Some refactoring.

This commit is contained in:
Andrey Egorov 2024-08-12 13:40:26 +03:00
parent d21ad0ce00
commit 5059814d39
9 changed files with 258 additions and 187 deletions

View File

@ -4,11 +4,11 @@ import (
"fmt"
"io"
"log"
"os"
"os/exec"
"strings"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/at"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/utils"
)
var apns = map[string]string{
@ -44,7 +44,8 @@ type conn struct {
type Conn interface {
Init() error
ConfigurePPP() error
Connect() error
Disconnect() error
Ping() bool // Is connected
io.Closer
}
@ -56,121 +57,14 @@ func New(logger *log.Logger, port at.Port) Conn {
}
}
func (c *conn) checkPackageExist(pname string) bool {
resp, err := exec.Command("apt-mark", "showmanual", pname).Output()
c.logger.Println("CHECK:", resp)
if err != nil {
c.logger.Println("CHECK PACKAGE ERROR: ", err.Error())
return false
}
return string(resp[:len(pname)]) == pname
}
func (c *conn) ensurePackage(pname string) error {
if c.checkPackageExist(pname) {
return nil
}
return fmt.Errorf("package %s not installed", pname)
// c.logger.Println("Installing", pname, "package...")
// resp, err := exec.Command("apt-get", "install", pname).Output()
// if err != nil {
// return fmt.Errorf("execute install cmd: %w", err)
// }
// c.logger.Println(resp)
// c.logger.Println("\x1b[38;2;255;0;0mComplete\x1b[38;2;255;255;255m")
// return nil
}
// Check requirenments
func (c *conn) checkReqs() error {
// Check AT port for sure
if c.port == nil || !c.port.IsConnected() {
return fmt.Errorf("AT port is not connect or nil")
func (c *conn) Connect() error {
if ok, err := utils.CheckService(c.port, c.logger); err != nil || !ok {
if err != nil {
return fmt.Errorf("check service: %w", err)
}
return fmt.Errorf("no service")
}
// Ensure all necessary packages installed
if err := c.ensurePackage("ppp"); err != nil {
return fmt.Errorf("ensure ppp package: %w", err)
}
// if err := c.ensurePackage("net-tools"); err != nil {
// return fmt.Errorf("ensure net-tools package: %w", err)
// }
// Check SIM is valid
// AT+CPIN? and just check
resp, err := c.port.Send("AT+CPIN?")
if err != nil {
return fmt.Errorf("AT+CPIN? request: %w", err)
}
if !resp.Check() {
return fmt.Errorf("validate SIM: error response: %s", resp)
}
return nil
}
func (c *conn) ConfigurePPP() error {
// Get provider name and its APN
resp, err := c.port.Send("AT+CSPN?")
if err != nil {
return fmt.Errorf("AT+CSPN? request: %w", err)
}
if !resp.Check() {
return fmt.Errorf("get provider: error response: %s", resp)
}
strs := strings.Split(string(resp), "\"")
if len(strs) < 3 {
return fmt.Errorf("parse AT+CSPN response: %s", string(resp))
}
provider := strs[1]
apn := apns[provider]
if apn == "" {
return fmt.Errorf("no apn for provider: %s", provider)
}
// Make config
c.logger.Printf("Config values: %s, %s, %d", apn, c.port.GetName(), c.port.GetBaudrate())
config := fmt.Sprintf(pppConfig, apn, c.port.GetName(), c.port.GetBaudrate())
// Write to file
f, err := os.OpenFile("/etc/ppp/peers/"+pppConfigName, os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
return fmt.Errorf("open ppp config file %w", err)
}
defer f.Close()
if _, err := f.Write([]byte(config)); err != nil {
return fmt.Errorf("write to ppp config file: %w", err)
}
return nil
}
func (c *conn) setup() error {
c.logger.Println("Check requirenments...")
if err := c.checkReqs(); err != nil {
return fmt.Errorf("check requirenments: %w", err)
}
// DEBUG show networks and signal
resp, err := c.port.Send("AT+COPS?")
if err != nil {
return fmt.Errorf("AT+COPS? request: %w", err)
}
c.logger.Println("DEBUG networks:", resp)
resp, err = c.port.Send("AT+CSQ")
if err != nil {
return fmt.Errorf("AT+CSQ request: %w", err)
}
c.logger.Println("DEBUG signal quality:", resp)
// Configure ppp
// what is better ASK If /etc/ppp/peers/annalistnet not exists
c.logger.Println("Configure ppp...")
if err := c.ConfigurePPP(); err != nil {
return fmt.Errorf("configure ppp: %w", err)
}
return nil
}
func (c *conn) connect() error {
resp, err := exec.Command("pon", pppConfigName).Output()
if err != nil {
return fmt.Errorf("execute connect cmd: %w", err)
@ -179,7 +73,7 @@ func (c *conn) connect() error {
return nil
}
func (c *conn) diconnect() error {
func (c *conn) Disconnect() error {
resp, err := exec.Command("poff", pppConfigName).Output()
if err != nil {
return fmt.Errorf("execute disconnect cmd: %w", err)
@ -190,28 +84,27 @@ func (c *conn) diconnect() error {
func (c *conn) Init() error {
// Setup
c.logger.Println("Setup...")
if err := c.setup(); err != nil {
return fmt.Errorf("setup: %w", err)
}
// Connect
c.logger.Println("Connect...")
if err := c.connect(); err != nil {
return fmt.Errorf("connect: %w", err)
}
// // Connect
// c.logger.Println("Connect...")
// if err := c.Connect(); err != nil {
// return fmt.Errorf("connect: %w", err)
// }
//DEBUG
resp, err := exec.Command("ifconfig").Output()
if err != nil {
return fmt.Errorf("execute ifconfig cmd: %w", err)
}
c.logger.Println("DEBUG ifconfig resp:", string(resp))
// //DEBUG
// resp, err := exec.Command("ifconfig").Output()
// if err != nil {
// return fmt.Errorf("execute ifconfig cmd: %w", err)
// }
// c.logger.Println("DEBUG ifconfig resp:", string(resp))
// Test connectin using Ping
c.logger.Println("Test...")
if !c.Ping() {
return fmt.Errorf("ping failed")
}
// // Test connectin using Ping
// c.logger.Println("Test...")
// if !c.Ping() {
// return fmt.Errorf("ping failed")
// }
return nil
}
@ -234,7 +127,7 @@ func (c *conn) Ping() bool {
}
func (c *conn) Close() error {
if err := c.diconnect(); err != nil {
if err := c.Disconnect(); err != nil {
return fmt.Errorf("diconnect: %w", err)
}
return nil

119
api/modem/internet/setup.go Normal file
View File

@ -0,0 +1,119 @@
package internet
import (
"fmt"
"os"
"os/exec"
"strings"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/utils"
)
func (c *conn) setup() error {
c.logger.Println("Check requirenments...")
if err := c.checkReqs(); err != nil {
return fmt.Errorf("check requirenments: %w", err)
}
// DEBUG show networks and signal
resp, err := c.port.Send("AT+COPS?")
if err != nil {
return fmt.Errorf("AT+COPS? request: %w", err)
}
c.logger.Println("DEBUG networks:", resp)
resp, err = c.port.Send("AT+CSQ")
if err != nil {
return fmt.Errorf("AT+CSQ request: %w", err)
}
c.logger.Println("DEBUG signal quality:", resp)
// Configure ppp
// what is better ASK If /etc/ppp/peers/annalistnet not exists
c.logger.Println("Configure ppp...")
if err := c.configurePPP(); err != nil {
return fmt.Errorf("configure ppp: %w", err)
}
return nil
}
// Check requirenments
func (c *conn) checkReqs() error {
// Check AT port for sure
if c.port == nil || !c.port.IsConnected() {
return fmt.Errorf("AT port is not connect or nil")
}
// Ensure all necessary packages installed
if err := c.ensurePackage("ppp"); err != nil {
return fmt.Errorf("ensure ppp package: %w", err)
}
// if err := c.ensurePackage("net-tools"); err != nil {
// return fmt.Errorf("ensure net-tools package: %w", err)
// }
// Check SIM is valid
if err := utils.CheckPIN(c.port, c.logger); err != nil {
return fmt.Errorf("PIN check: %w", err)
}
return nil
}
func (c *conn) ensurePackage(pname string) error {
if c.checkPackageExist(pname) {
return nil
}
return fmt.Errorf("package %s not installed", pname)
// c.logger.Println("Installing", pname, "package...")
// resp, err := exec.Command("apt-get", "install", pname).Output()
// if err != nil {
// return fmt.Errorf("execute install cmd: %w", err)
// }
// c.logger.Println(resp)
// c.logger.Println("\x1b[38;2;255;0;0mComplete\x1b[38;2;255;255;255m")
// return nil
}
func (c *conn) checkPackageExist(pname string) bool {
resp, err := exec.Command("apt-mark", "showmanual", pname).Output()
c.logger.Println("CHECK:", resp)
if err != nil {
c.logger.Println("CHECK PACKAGE ERROR: ", err.Error())
return false
}
return string(resp[:len(pname)]) == pname
}
func (c *conn) configurePPP() error {
// Get provider name and its APN
resp, err := c.port.Send("AT+CSPN?")
if err != nil {
return fmt.Errorf("AT+CSPN? request: %w", err)
}
if !resp.Check() {
return fmt.Errorf("get provider: error response: %s", resp)
}
strs := strings.Split(string(resp), "\"")
if len(strs) < 3 {
return fmt.Errorf("parse AT+CSPN response: %s", string(resp))
}
provider := strs[1]
apn := apns[provider]
if apn == "" {
return fmt.Errorf("no apn for provider: %s", provider)
}
// Make config
c.logger.Printf("Config values: %s, %s, %d", apn, c.port.GetName(), c.port.GetBaudrate())
config := fmt.Sprintf(pppConfig, apn, c.port.GetName(), c.port.GetBaudrate())
// Write to file
f, err := os.OpenFile("/etc/ppp/peers/"+pppConfigName, os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
return fmt.Errorf("open ppp config file %w", err)
}
defer f.Close()
if _, err := f.Write([]byte(config)); err != nil {
return fmt.Errorf("write to ppp config file: %w", err)
}
return nil
}

View File

@ -15,7 +15,6 @@ import (
"gitea.unprism.ru/KRBL/sim-modem/api/modem/gps"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/internet"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/sms"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/utils"
)
type ModemData struct {
@ -54,7 +53,6 @@ type Modem interface {
IsConnected() bool
Update() error
GetData() ModemData
CheckSignal() error
PowerOn() error
PowerOff() error
@ -120,13 +118,19 @@ func (m *modem) Init() error {
// } else {
// m.logger.Println("\x1b[38;2;0;255;0mInternet OK\x1b[38;2;255;255;255m")
// }
//
// if err := m.ic.Connect(); err != nil {
// m.logger.Println("connect to internet: %w", err)
// } else {
// m.logger.Println("internet connected")
// }
m.sms = sms.New(log.New(submodulesLogger, "modem-sms : ", log.LstdFlags), m.port)
if err := m.sms.Init(); err != nil {
m.logger.Printf("\x1b[38;2;255;0;0mSMS: %s\x1b[38;2;255;255;255m\n", err.Error())
} else {
m.logger.Println("\x1b[38;2;0;255;0mSMS OK\x1b[38;2;255;255;255m")
}
// m.sms = sms.New(log.New(submodulesLogger, "modem-sms : ", log.LstdFlags), m.port)
// if err := m.sms.Init(); err != nil {
// m.logger.Printf("\x1b[38;2;255;0;0mSMS: %s\x1b[38;2;255;255;255m\n", err.Error())
// } else {
// m.logger.Println("\x1b[38;2;0;255;0mSMS OK\x1b[38;2;255;255;255m")
// }
m.gps = gps.New(log.New(submodulesLogger, "modem-gps : ", log.LstdFlags), m.port)
if err := m.gps.Init(); err != nil {
@ -172,10 +176,6 @@ func (m *modem) GetData() ModemData {
}
}
func (m *modem) CheckSignal() error {
return utils.CheckSignal(m.port, m.logger)
}
func (m *modem) PowerOn() error {
m.onOffPin.PowerOn() // DEBUG do not want to wait 30 seconds
return nil

View File

@ -6,23 +6,6 @@ import (
"strings"
)
func (d *dialer) checkPIN() error {
// Get code
resp, err := d.port.Send("AT+CPIN?")
if err != nil {
return fmt.Errorf("AT+CPIN? request: %w", err)
}
if !resp.Check() || !resp.CheckFront("+CPIN:") {
return fmt.Errorf("AT+CPIN? error response: %s", resp)
}
code := strings.ReplaceAll(strings.ReplaceAll(strings.Split(resp.RmFront("+CPIN:").String(), "\n")[0], "\r", ""), " ", "")
if code != "READY" {
return fmt.Errorf("not READY code: %s", code)
}
d.logger.Println("PIN is ready")
return nil
}
func (d *dialer) setupMsgSt() error {
// Check for free space for messages
// !!! I use one! memory for all three bindings

View File

@ -8,6 +8,7 @@ import (
"time"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/at"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/utils"
)
type dialer struct {
@ -36,7 +37,7 @@ func (d *dialer) Init() error {
return fmt.Errorf("serial port is not connected")
}
// Check ping
if err := d.checkPIN(); err != nil {
if err := utils.CheckPIN(d.port, d.logger); err != nil {
return fmt.Errorf("check PIN: %w", err)
}
// Setup prefered message storage

View File

@ -0,0 +1,37 @@
package utils
import (
"fmt"
"log"
"strings"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/at"
)
func CheckService(port at.Port, logger *log.Logger) (bool, error) {
srv, err := getService(port)
if err != nil {
return false, fmt.Errorf("get service: %w", err)
}
if srv == "NO SERVICE" {
return false, nil
}
logger.Println("Current service:", srv)
return true, nil
}
// Returns service
func getService(port at.Port) (string, error) {
resp, err := port.Send("AT+CPSI?")
if err != nil {
return "", err
}
if !resp.Check() || !resp.CheckFront("+CPSI: ") {
return "", fmt.Errorf("error response: %s", resp)
}
values := strings.Split(strings.ReplaceAll(strings.Split(resp.RmFront("+CPSI: ").String(), "\n")[0], "\r", ""), ",")
if len(values) < 2 {
return "", fmt.Errorf("invalid values(len): [% s]", values)
}
return values[0], nil
}

View File

@ -9,19 +9,19 @@ import (
"gitea.unprism.ru/KRBL/sim-modem/api/modem/at"
)
func CheckSignal(port at.Port, logger *log.Logger) error {
func CheckSignal(port at.Port, logger *log.Logger) (bool, error) {
rssi, ber, err := getSignalQuality(port)
if err != nil {
return fmt.Errorf("get signal quality: %w", err)
return false, fmt.Errorf("get signal quality: %w", err)
}
logger.Printf("check signal: rssi=%d ber=%d\n", rssi, ber)
if err := checkRssi(rssi); err != nil {
return fmt.Errorf("rssi: %w", err)
return false, nil
}
if err := checkBer(ber); err != nil {
logger.Printf("bad ber(not critical): %s", err.Error()) // Happened not to be critical
}
return nil
return true, nil
}
func checkRssi(rssi int) error {
@ -84,6 +84,7 @@ func checkBer(ber int) error {
return fmt.Errorf("invalid code %d", ber)
}
// Returns rssi and ber(look above)
func getSignalQuality(port at.Port) (int, int, error) {
resp, err := port.Send("AT+CSQ")
if err != nil {

26
api/modem/utils/sim.go Normal file
View File

@ -0,0 +1,26 @@
package utils
import (
"fmt"
"log"
"strings"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/at"
)
func CheckPIN(port at.Port, logger *log.Logger) error {
// Get code
resp, err := port.Send("AT+CPIN?")
if err != nil {
return fmt.Errorf("AT+CPIN? request: %w", err)
}
if !resp.Check() || !resp.CheckFront("+CPIN:") {
return fmt.Errorf("AT+CPIN? error response: %s", resp)
}
code := strings.ReplaceAll(strings.ReplaceAll(strings.Split(resp.RmFront("+CPIN:").String(), "\n")[0], "\r", ""), " ", "")
if code != "READY" {
return fmt.Errorf("not READY code: %s", code)
}
logger.Println("PIN is ready")
return nil
}

49
main.go
View File

@ -1,8 +1,11 @@
package main
import (
"context"
"log"
"os"
"os/signal"
"syscall"
"time"
"gitea.unprism.ru/KRBL/sim-modem/api/modem"
@ -11,13 +14,17 @@ import (
func main() {
log.Println("CGSG forever!!!")
if err := mainE(); err != nil {
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer cancel()
if err := mainE(ctx); err != nil {
log.Println("MAIN finished with error:", err.Error())
}
log.Println("END")
}
func mainE() error {
func mainE(ctx context.Context) error {
logger := log.New(os.Stdout, "main : ", log.LstdFlags)
m := modem.New(log.New(logger.Writer(), "modem : ", log.LstdFlags))
@ -61,30 +68,34 @@ func mainE() error {
// logger.Println(m.Sms().Send("+79218937173", "CGSG forever!!!"))
// m.At().RawSend("\r\n\x1A\r\n")
Cmd("AT+CREG?")
Cmd("AT+CNMI?")
Cmd("AT+CSQ")
Cmd("AT+CSCA?")
Cmd("AT+CPOL?")
Cmd("AT+COPS?")
// Cmd("AT+COPS=?")
Cmd("AT+CPSI?")
resp, err = m.At().Send("AT+CNMI=2,2")
// Cmd("AT+CREG?")
// Cmd("AT+CNMI?")
// Cmd("AT+CSQ")
// Cmd("AT+CSCA?")
// Cmd("AT+CPOL?")
// Cmd("AT+COPS?")
// // Cmd("AT+COPS=?")
// Cmd("AT+CPSI?")
// resp, err = m.At().Send("AT+CNMI=2,2")
for {
// Cmd("AT+CSQ")
// Cmd("AT+COPS?")
Cmd("AT+CPSI?")
// if err := m.CheckSignal(); err != nil {
// logger.Println(err)
// } else {
// logger.Println("AAAAAAAAAAA THERE IS SIGNAL")
// }
// time.Sleep(250 * time.Millisecond)
readLen, err := m.At().SerialPort().Read(buf)
if err != nil {
return err
}
if readLen > 0 {
logger.Println(string(buf[:readLen]))
}
time.Sleep(500 * time.Millisecond)
// readLen, err := m.At().SerialPort().Read(buf)
// if err != nil {
// return err
// }
// if readLen > 0 {
// logger.Println(string(buf[:readLen]))
// }
}
// resp, err = m.At().Send("AT+CPMS?")