From 92d42d413ae4bf17e29fc0f055f05e9f00cbbf52 Mon Sep 17 00:00:00 2001 From: Andrey Egorov Date: Sat, 27 Jul 2024 16:01:27 +0300 Subject: [PATCH] Added internet connection(not debugged yet). --- api/modem/at/at.go | 5 + api/modem/internet/ic.go | 219 +++++++++++++++++++++++++++++++++++++++ api/modem/modem.go | 35 +++++-- 3 files changed, 250 insertions(+), 9 deletions(-) create mode 100644 api/modem/internet/ic.go diff --git a/api/modem/at/at.go b/api/modem/at/at.go index 9de1ce7..25e4625 100644 --- a/api/modem/at/at.go +++ b/api/modem/at/at.go @@ -26,6 +26,7 @@ type atPort struct { type Port interface { GetName() string + GetBaudrate() int GetSerialPort() serial.Port // For extra need Connect() error @@ -50,6 +51,10 @@ func (p *atPort) GetName() string { return p.portName } +func (p *atPort) GetBaudrate() int { + return p.baudrate +} + func (p *atPort) GetSerialPort() serial.Port { return p.port } diff --git a/api/modem/internet/ic.go b/api/modem/internet/ic.go new file mode 100644 index 0000000..32a65fe --- /dev/null +++ b/api/modem/internet/ic.go @@ -0,0 +1,219 @@ +package internet + +import ( + "fmt" + "io" + "log" + "os" + "os/exec" + "strings" + + "github.com/CGSG-2021-AE4/modem-test/api/modem/at" +) + +var apns = map[string]string{ + "tinkoff": "m.tinkoff", +} + +const pppConfigName = "annalistnet" +const pppConfig = ` +# Annalist project custom internet connection + +# APN: +connect "/usr/sbin/chat -v -f /etc/chatscripts/gprs -T %s" + +# Port: +%s + +# Baudrate: +%d + +noipdefault +usepeerdns +defaultroute +persist +noauth +nocrtscts +local +` + +type conn struct { + logger *log.Logger + port at.Port +} + +type Conn interface { + Init() error + ConfigurePPP() error + Ping() bool // Is connected + io.Closer +} + +func New(logger *log.Logger, port at.Port) Conn { + return &conn{ + logger: logger, + port: port, + } +} + +func (c *conn) checkPackageExist(pname string) bool { + resp, err := exec.Command("sudo", "apt-mark", "showmanual", pname).Output() + if err != nil { + c.logger.Println("CHECK PACKAGE ERROR: ", err.Error()) + return false + } + return string(resp) == pname +} + +func (c *conn) ensurePackage(pname string) error { + if c.checkPackageExist(pname) { + return nil + } + c.logger.Println("Installing", pname, "package...") + resp, err := exec.Command("sudo", "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") + } + + // 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("SIM card is not inserted") + } + return nil +} + +func (c *conn) ConfigurePPP() error { + // Get provider name and its APN + // AT+CSPN + provider := "" + apn := apns[provider] + if apn == "" { + return fmt.Errorf("no apn for provider: %s", provider) + } + config := fmt.Sprintf(pppConfig, apn, c.port.GetName(), c.port.GetBaudrate()) + + f, err := os.OpenFile("etc/ppp/pears/"+pppConfigName, os.O_CREATE, 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("sudo", "pon", pppConfigName).Output() + if err != nil { + return fmt.Errorf("execute connect cmd: %w", err) + } + c.logger.Println("DEBUG pon response:", resp) + return nil +} + +func (c *conn) diconnect() error { + resp, err := exec.Command("sudo", "poff", pppConfigName).Output() + if err != nil { + return fmt.Errorf("execute disconnect cmd: %w", err) + } + c.logger.Println("DEBUG poff response:", resp) + return nil +} + +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) + } + + //DEBUG + resp, err := exec.Command("ifconfig").Output() + if err != nil { + return fmt.Errorf("execute ifconfig cmd: %w", err) + } + c.logger.Println("DEBUG ifconfig resp:", resp) + + // Test connectin using Ping + c.logger.Println("Test...") + if !c.Ping() { + return fmt.Errorf("ping failed") + } + return nil +} + +func (c *conn) Ping() bool { + // Test - try to connect to Google DNS + // ping -I ppp0 8.8.8.8 + resp, err := exec.Command("ping", "-I", "ppp0", "8.8.8.8").Output() + if err != nil { + c.logger.Println("Ping cmd error:", err) + } + c.logger.Println("Ping resp:", resp) + + return !strings.Contains(string(resp), "Destination Host Unreachable") // tmp solution +} + +func (c *conn) Close() error { + if err := c.diconnect(); err != nil { + return fmt.Errorf("diconnect: %w", err) + } + return nil +} diff --git a/api/modem/modem.go b/api/modem/modem.go index b89f0bc..3df5486 100644 --- a/api/modem/modem.go +++ b/api/modem/modem.go @@ -11,6 +11,7 @@ import ( "github.com/CGSG-2021-AE4/modem-test/api/modem/at" "github.com/CGSG-2021-AE4/modem-test/api/modem/gpio" + "github.com/CGSG-2021-AE4/modem-test/api/modem/internet" ) type ModemData struct { @@ -32,8 +33,13 @@ type modem struct { onOffPin gpio.Pin // Other values - gpsInfo GpsData lastUpdateTime time.Time + + // GPS + gpsInfo GpsData + + // Internet connection + ic internet.Conn } type Modem interface { @@ -48,14 +54,14 @@ func New(logger *log.Logger) Modem { return &modem{ logger: logger, baudrate: 115200, - onOffPin: gpio.New(logger, 6), + onOffPin: gpio.New(log.New(logger.Writer(), "gpio", log.LstdFlags), 6), lastUpdateTime: time.Now(), } } func (m *modem) Init() error { // Turn module on - log.Println("=============================== Turn on module") + m.logger.Println("=============================== Turn on module") if err := m.onOffPin.Init(); err != nil { return fmt.Errorf("gpio pin init: %w", err) } @@ -88,6 +94,13 @@ func (m *modem) Init() error { if err := m.testGPS(); err != nil { return fmt.Errorf("testGPS: %w", err) } + + // Establish internet connection + m.logger.Println("=============================== Internet") + m.ic = internet.New(log.New(m.logger.Writer(), "internet", log.LstdFlags), m.port) + if err := m.Init(); err != nil { + return fmt.Errorf("internet connection init: %w", err) + } return nil } @@ -145,23 +158,27 @@ func (m *modem) GetInfo() ModemData { func (m *modem) Close() error { // Not right way I think if err := m.port.Close(); err != nil { - return err + return fmt.Errorf("serial port: %w", err) } if err := m.onOffPin.Close(); err != nil { - return err + return fmt.Errorf("gpio pin: %w", err) } + if err := m.ic.Close(); err != nil { + return fmt.Errorf("internet connection: %w", err) + } + return nil } func (m *modem) connect() error { - if !m.Validate() { + if m.port == nil { return fmt.Errorf("port is not defined") } return m.port.Connect() } func (m *modem) disconnect() error { - if !m.Validate() { + if m.port == nil { return fmt.Errorf("port is not defined") } return m.port.Disconnect() @@ -218,8 +235,8 @@ func (m *modem) testConsole() { if err != nil { m.logger.Println("ERROR:", err.Error()) } - log.Println(resp) - log.Println("------------------") + m.logger.Println(resp) + m.logger.Println("------------------") } }