Compare commits
	
		
			11 Commits
		
	
	
		
			781d9ccda4
			...
			fd9e999b5a
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | fd9e999b5a | ||
|  | d05e2205d6 | ||
|  | 1b741c7dab | ||
|  | e0110c558e | ||
|  | 225a0d2264 | ||
|  | 2eb21228e3 | ||
|  | ebab41c510 | ||
|  | 92d42d413a | ||
|  | b9056d2299 | ||
|  | 12555f2f46 | ||
|  | eb899f0b45 | 
| @@ -4,6 +4,11 @@ WORKDIR /app | |||||||
| COPY ./ ./ | COPY ./ ./ | ||||||
| RUN go mod download | RUN go mod download | ||||||
|  |  | ||||||
|  | RUN apt-get update | ||||||
|  | RUN apt-get install -y iputils-ping | ||||||
|  | RUN apt-get install -y ppp | ||||||
|  | RUN apt-get install -y net-tools | ||||||
|  |  | ||||||
|  |  | ||||||
| RUN CGO_ENABLED=0 GOOS=linux go build -o /modem-test | RUN CGO_ENABLED=0 GOOS=linux go build -o /modem-test | ||||||
|  |  | ||||||
|   | |||||||
| @@ -26,12 +26,14 @@ type atPort struct { | |||||||
|  |  | ||||||
| type Port interface { | type Port interface { | ||||||
| 	GetName() string | 	GetName() string | ||||||
|  | 	GetBaudrate() int | ||||||
| 	GetSerialPort() serial.Port // For extra need | 	GetSerialPort() serial.Port // For extra need | ||||||
|  |  | ||||||
| 	Connect() error | 	Connect() error | ||||||
| 	Disconnect() error | 	Disconnect() error | ||||||
| 	IsConnected() bool | 	IsConnected() bool | ||||||
|  |  | ||||||
|  | 	RawSend(msg string) (string, error) | ||||||
| 	Send(cmd string) (Resp, error) | 	Send(cmd string) (Resp, error) | ||||||
|  |  | ||||||
| 	io.Closer | 	io.Closer | ||||||
| @@ -50,6 +52,10 @@ func (p *atPort) GetName() string { | |||||||
| 	return p.portName | 	return p.portName | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (p *atPort) GetBaudrate() int { | ||||||
|  | 	return p.baudrate | ||||||
|  | } | ||||||
|  |  | ||||||
| func (p *atPort) GetSerialPort() serial.Port { | func (p *atPort) GetSerialPort() serial.Port { | ||||||
| 	return p.port | 	return p.port | ||||||
| } | } | ||||||
| @@ -84,15 +90,15 @@ func (p *atPort) IsConnected() bool { | |||||||
| } | } | ||||||
|  |  | ||||||
| // Low level write/read function | // Low level write/read function | ||||||
| func (p *atPort) makeReq(msg string) (string, error) { | func (p *atPort) RawSend(msg string) (string, error) { | ||||||
| 	// Write | 	// Write | ||||||
| 	p.port.ResetInputBuffer() |  | ||||||
| 	if _, err := p.port.Write([]byte(msg)); err != nil { | 	if _, err := p.port.Write([]byte(msg)); err != nil { | ||||||
| 		return "", fmt.Errorf("serial port write: %w", err) | 		return "", fmt.Errorf("serial port write: %w", err) | ||||||
| 	} | 	} | ||||||
|  | 	time.Sleep(time.Millisecond) | ||||||
| 	// Read | 	// Read | ||||||
| 	readLen, err := p.port.Read(p.inputBuf) | 	readLen, err := p.port.Read(p.inputBuf) | ||||||
| 	p.logger.Println(msg, "RAWREAD:", string(p.inputBuf[:readLen])) | 	// p.logger.Println(msg, "\x1b[38;2;150;150;150mRAWREAD:", string(p.inputBuf[:readLen]), "\x1b[38;2;255;255;255m") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", fmt.Errorf("port read: %w", err) | 		return "", fmt.Errorf("port read: %w", err) | ||||||
| 	} | 	} | ||||||
| @@ -102,12 +108,12 @@ func (p *atPort) makeReq(msg string) (string, error) { | |||||||
|  |  | ||||||
| func (p *atPort) Send(cmd string) (Resp, error) { | func (p *atPort) Send(cmd string) (Resp, error) { | ||||||
| 	cmd += "\r\n" | 	cmd += "\r\n" | ||||||
| 	rawResp, err := p.makeReq(cmd) | 	rawResp, err := p.RawSend(cmd) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return RespNil, fmt.Errorf("make request: %w", err) | 		return RespNil, fmt.Errorf("make request: %w", err) | ||||||
| 	} | 	} | ||||||
| 	if len(rawResp) <= 4 { | 	if len(rawResp) <= 4 { | ||||||
| 		return RespNil, fmt.Errorf("read too small msg: %d byte", len(rawResp)) | 		return RespNil, fmt.Errorf("read too small msg: %d byte - %s", len(rawResp), string(rawResp)) | ||||||
| 	} | 	} | ||||||
| 	resp := rawResp[2 : len(rawResp)-2] // Cut \r\n | 	resp := rawResp[2 : len(rawResp)-2] // Cut \r\n | ||||||
|  |  | ||||||
|   | |||||||
| @@ -15,3 +15,7 @@ func (resp Resp) RmFront(str string) Resp { | |||||||
| func (resp Resp) String() string { | func (resp Resp) String() string { | ||||||
| 	return string(resp) | 	return string(resp) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (resp Resp) Bytes() []byte { | ||||||
|  | 	return []byte(resp) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package modem | package gpio | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"io" | ||||||
| 	"log" | 	"log" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| @@ -9,7 +10,21 @@ import ( | |||||||
| 
 | 
 | ||||||
| type gpioPin struct { | type gpioPin struct { | ||||||
| 	logger *log.Logger | 	logger *log.Logger | ||||||
| 	Pin    gpio.Pin | 	pin    gpio.Pin | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type Pin interface { | ||||||
|  | 	Init() error | ||||||
|  | 	PowerOn() | ||||||
|  | 	PowerOff() | ||||||
|  | 	io.Closer | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func New(logger *log.Logger, pin uint8) Pin { | ||||||
|  | 	return gpioPin{ | ||||||
|  | 		logger: logger, | ||||||
|  | 		pin:    gpio.Pin(pin), | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p gpioPin) Init() error { | func (p gpioPin) Init() error { | ||||||
| @@ -17,20 +32,20 @@ func (p gpioPin) Init() error { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p gpioPin) sendOnOffSignal() { | func (p gpioPin) sendOnOffSignal() { | ||||||
| 	p.Pin.Output() | 	p.pin.Output() | ||||||
| 	p.logger.Println("Power on 0/3 + 100ms") | 	p.logger.Println("Power on 0/3 + 100ms") | ||||||
| 	p.Pin.Low() | 	p.pin.Low() | ||||||
| 	p.Pin.Toggle() | 	p.pin.Toggle() | ||||||
| 	time.Sleep(100 * time.Millisecond) | 	time.Sleep(100 * time.Millisecond) | ||||||
| 
 | 
 | ||||||
| 	p.logger.Println("Power on 1/3 + 3s") | 	p.logger.Println("Power on 1/3 + 3s") | ||||||
| 	p.Pin.High() | 	p.pin.High() | ||||||
| 	p.Pin.Toggle() | 	p.pin.Toggle() | ||||||
| 	time.Sleep(3 * time.Second) | 	time.Sleep(3 * time.Second) | ||||||
| 
 | 
 | ||||||
| 	p.logger.Println("Power on 2/3 + 30s") | 	p.logger.Println("Power on 2/3 + 30s") | ||||||
| 	p.Pin.Low() | 	p.pin.Low() | ||||||
| 	p.Pin.Toggle() | 	p.pin.Toggle() | ||||||
| 	time.Sleep(30 * time.Second) | 	time.Sleep(30 * time.Second) | ||||||
| 
 | 
 | ||||||
| 	p.logger.Println("Power on 3/3") | 	p.logger.Println("Power on 3/3") | ||||||
| @@ -40,10 +55,10 @@ func (p gpioPin) PowerOn() { | |||||||
| 	p.sendOnOffSignal() | 	p.sendOnOffSignal() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *gpioPin) PowerOff() { | func (p gpioPin) PowerOff() { | ||||||
| 	p.sendOnOffSignal() | 	p.sendOnOffSignal() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *gpioPin) Close() error { | func (p gpioPin) Close() error { | ||||||
| 	return gpio.Close() | 	return gpio.Close() | ||||||
| } | } | ||||||
| @@ -6,6 +6,8 @@ import ( | |||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/CGSG-2021-AE4/modem-test/api/modem/at" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type GpsData struct { | type GpsData struct { | ||||||
| @@ -37,6 +39,7 @@ func (gps *GpsData) calculateSpeed(newLatitude, newLongitude float64, lastUpdate | |||||||
| 	gps.Speed = earthRad * c / (math.Abs(float64(time.Since(lastUpdateTime)))) | 	gps.Speed = earthRad * c / (math.Abs(float64(time.Since(lastUpdateTime)))) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Parse string from AT command that contains gps data | ||||||
| func (gps *GpsData) decode(str string) error { | func (gps *GpsData) decode(str string) error { | ||||||
| 	var err error | 	var err error | ||||||
| 	newGpsInfo := GpsData{} | 	newGpsInfo := GpsData{} | ||||||
| @@ -50,8 +53,10 @@ func (gps *GpsData) decode(str string) error { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("parse longitude: %w", err) | 		return fmt.Errorf("parse longitude: %w", err) | ||||||
| 	} | 	} | ||||||
|  | 	newGpsInfo.Latitude /= 100 | ||||||
|  | 	newGpsInfo.Longitude /= 100 | ||||||
| 	newGpsInfo.LatitudeIndicator = strs[1] | 	newGpsInfo.LatitudeIndicator = strs[1] | ||||||
| 	newGpsInfo.LatitudeIndicator = strs[3] | 	newGpsInfo.LongitudeIndicator = strs[3] | ||||||
| 	newGpsInfo.Date = strs[4] | 	newGpsInfo.Date = strs[4] | ||||||
| 	newGpsInfo.Time = strs[5] | 	newGpsInfo.Time = strs[5] | ||||||
| 	newGpsInfo.Altitude, err = strconv.ParseFloat(strs[6], 64) | 	newGpsInfo.Altitude, err = strconv.ParseFloat(strs[6], 64) | ||||||
| @@ -72,3 +77,61 @@ func (gps *GpsData) decode(str string) error { | |||||||
| 	*gps = newGpsInfo | 	*gps = newGpsInfo | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (gps *GpsData) Update(port at.Port) error { | ||||||
|  | 	if err := switchGpsMode(port, true); err != nil { | ||||||
|  | 		return fmt.Errorf("try to GPS mode: %w", err) | ||||||
|  | 	} | ||||||
|  | 	defer switchGpsMode(port, false) | ||||||
|  |  | ||||||
|  | 	resp, err := port.Send("AT+CGPSINFO") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("receive GPS data: %w", err) | ||||||
|  | 	} | ||||||
|  | 	if !resp.Check() { | ||||||
|  | 		return fmt.Errorf("error response") | ||||||
|  | 	} | ||||||
|  | 	if err := gps.decode(strings.Split(strings.Replace(resp.RmFront("+CGPSINFO:").String(), "\r", "", -1), "\n")[0]); err != nil { | ||||||
|  | 		return fmt.Errorf("decode: %w", err) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func switchGpsMode(port at.Port, on bool) error { | ||||||
|  | 	onStr := "0" | ||||||
|  | 	if on { | ||||||
|  | 		onStr = "1" | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Reset input | ||||||
|  | 	if err := port.GetSerialPort().ResetInputBuffer(); err != nil { | ||||||
|  | 		return fmt.Errorf("reset input buffer: %w", err) | ||||||
|  | 	} | ||||||
|  | 	// Reset output | ||||||
|  | 	if err := port.GetSerialPort().ResetOutputBuffer(); err != nil { | ||||||
|  | 		return fmt.Errorf("reset output buffer: %w", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Check gps mode status | ||||||
|  | 	resp, err := port.Send("AT+CGPS?") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("make at ask: %w", err) | ||||||
|  | 	} | ||||||
|  | 	if !resp.Check() { | ||||||
|  | 		return fmt.Errorf("error response") | ||||||
|  | 	} | ||||||
|  | 	ans := strings.Replace(strings.Split(strings.Split(resp.RmFront("+CGPS:").String(), "\n")[0], ",")[0], " ", "", -1) | ||||||
|  | 	if ans == onStr { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Modem is not in GPS mode | ||||||
|  | 	resp, err = port.Send("AT+CGPS=" + onStr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("try to switch to gps: %w", err) | ||||||
|  | 	} | ||||||
|  | 	if !resp.Check() { | ||||||
|  | 		return fmt.Errorf("switch tp GPS failed") | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										242
									
								
								api/modem/internet/ic.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										242
									
								
								api/modem/internet/ic.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,242 @@ | |||||||
|  | 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("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") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// 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 | ||||||
|  | 	resp, err := c.port.Send("AT+CSPN?") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("AT+CSPN? request: %w", err) | ||||||
|  | 	} | ||||||
|  | 	if !resp.Check() { | ||||||
|  | 		return fmt.Errorf("failed to check SIM provider") | ||||||
|  | 	} | ||||||
|  | 	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) | ||||||
|  | 	} | ||||||
|  | 	c.logger.Println("DEBUG pon response:", string(resp)) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *conn) diconnect() error { | ||||||
|  | 	resp, err := exec.Command("poff", pppConfigName).Output() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("execute disconnect cmd: %w", err) | ||||||
|  | 	} | ||||||
|  | 	c.logger.Println("DEBUG poff response:", string(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:", string(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", "8.8.8.8").Output() | ||||||
|  | 	if err != nil { | ||||||
|  | 		c.logger.Println("Ping 1 cmd error:", err) | ||||||
|  | 	} | ||||||
|  | 	c.logger.Println("Ping 1 resp:", string(resp)) | ||||||
|  |  | ||||||
|  | 	resp, err = exec.Command("ping", "-I", "ppp0", "8.8.8.8").Output() | ||||||
|  | 	if err != nil { | ||||||
|  | 		c.logger.Println("Ping 2 cmd error:", err) | ||||||
|  | 	} | ||||||
|  | 	c.logger.Println("Ping 2 resp:", string(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 | ||||||
|  | } | ||||||
| @@ -10,6 +10,9 @@ import ( | |||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/CGSG-2021-AE4/modem-test/api/modem/at" | 	"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" | ||||||
|  | 	"github.com/CGSG-2021-AE4/modem-test/api/modem/sms" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type ModemData struct { | type ModemData struct { | ||||||
| @@ -28,11 +31,19 @@ type modem struct { | |||||||
| 	port       at.Port | 	port       at.Port | ||||||
|  |  | ||||||
| 	// Gpio values | 	// Gpio values | ||||||
| 	onOffPin gpioPin | 	onOffPin gpio.Pin | ||||||
|  |  | ||||||
| 	// Other values | 	// Other values | ||||||
| 	gpsInfo        GpsData |  | ||||||
| 	lastUpdateTime time.Time | 	lastUpdateTime time.Time | ||||||
|  |  | ||||||
|  | 	// GPS | ||||||
|  | 	gpsInfo GpsData | ||||||
|  |  | ||||||
|  | 	// Internet connection | ||||||
|  | 	ic internet.Conn | ||||||
|  |  | ||||||
|  | 	// Sms and calls | ||||||
|  | 	sms sms.Dialer | ||||||
| } | } | ||||||
|  |  | ||||||
| type Modem interface { | type Modem interface { | ||||||
| @@ -40,6 +51,11 @@ type Modem interface { | |||||||
| 	Validate() bool | 	Validate() bool | ||||||
| 	Update() error | 	Update() error | ||||||
| 	GetInfo() ModemData | 	GetInfo() ModemData | ||||||
|  |  | ||||||
|  | 	// Temp access to SMS and AT interface | ||||||
|  | 	Sms() sms.Dialer | ||||||
|  | 	At() at.Port | ||||||
|  |  | ||||||
| 	io.Closer | 	io.Closer | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -47,18 +63,18 @@ func New(logger *log.Logger) Modem { | |||||||
| 	return &modem{ | 	return &modem{ | ||||||
| 		logger:         logger, | 		logger:         logger, | ||||||
| 		baudrate:       115200, | 		baudrate:       115200, | ||||||
| 		onOffPin:       gpioPin{Pin: 6}, | 		onOffPin:       gpio.New(log.New(logger.Writer(), "gpio", log.LstdFlags), 6), | ||||||
| 		lastUpdateTime: time.Now(), | 		lastUpdateTime: time.Now(), | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *modem) Init() error { | func (m *modem) Init() error { | ||||||
| 	// Turn module on | 	// Turn module on | ||||||
| 	// log.Println("=============================== Turn on module") | 	m.logger.Println("=============================== Turn on module") | ||||||
| 	// if err := m.onOffPin.Init(); err != nil { | 	if err := m.onOffPin.Init(); err != nil { | ||||||
| 	// 	return fmt.Errorf("gpio pin init: %w", err) | 		return fmt.Errorf("gpio pin init: %w", err) | ||||||
| 	// } | 	} | ||||||
| 	// onOffPin.PowerOn() | 	// m.onOffPin.PowerOn() | ||||||
|  |  | ||||||
| 	// Search | 	// Search | ||||||
| 	m.logger.Println("=============================== Search") | 	m.logger.Println("=============================== Search") | ||||||
| @@ -87,6 +103,19 @@ func (m *modem) Init() error { | |||||||
| 	if err := m.testGPS(); err != nil { | 	if err := m.testGPS(); err != nil { | ||||||
| 		return fmt.Errorf("testGPS: %w", err) | 		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.ic.Init(); err != nil { | ||||||
|  | 	// 	return fmt.Errorf("internet connection init: %w", err) | ||||||
|  | 	// } | ||||||
|  |  | ||||||
|  | 	// Init sms dialer | ||||||
|  | 	m.sms = sms.New(log.New(m.logger.Writer(), "sms", log.LstdFlags), m.port) | ||||||
|  | 	if err := m.sms.Init(); err != nil { | ||||||
|  | 		return fmt.Errorf("sms dialer init %w", err) | ||||||
|  | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -141,26 +170,42 @@ func (m *modem) GetInfo() ModemData { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (m *modem) Sms() sms.Dialer { | ||||||
|  | 	return m.sms | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *modem) At() at.Port { | ||||||
|  | 	return m.port | ||||||
|  | } | ||||||
|  |  | ||||||
| func (m *modem) Close() error { | func (m *modem) Close() error { | ||||||
|  | 	if err := m.sms.Close(); err != nil { | ||||||
|  | 		return fmt.Errorf("sms: %w", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// Not right way I think | 	// Not right way I think | ||||||
| 	if err := m.port.Close(); err != nil { | 	if err := m.port.Close(); err != nil { | ||||||
| 		return err | 		return fmt.Errorf("serial port: %w", err) | ||||||
| 	} | 	} | ||||||
| 	if err := m.onOffPin.Close(); err != nil { | 	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 | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *modem) connect() error { | func (m *modem) connect() error { | ||||||
| 	if !m.Validate() { | 	if m.port == nil { | ||||||
| 		return fmt.Errorf("port is not defined") | 		return fmt.Errorf("port is not defined") | ||||||
| 	} | 	} | ||||||
| 	return m.port.Connect() | 	return m.port.Connect() | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *modem) disconnect() error { | func (m *modem) disconnect() error { | ||||||
| 	if !m.Validate() { | 	if m.port == nil { | ||||||
| 		return fmt.Errorf("port is not defined") | 		return fmt.Errorf("port is not defined") | ||||||
| 	} | 	} | ||||||
| 	return m.port.Disconnect() | 	return m.port.Disconnect() | ||||||
| @@ -176,10 +221,6 @@ func (m *modem) isConnected() bool { | |||||||
| func (m *modem) testGPS() error { | func (m *modem) testGPS() error { | ||||||
| 	m.logger.Println("Testing GPS") | 	m.logger.Println("Testing GPS") | ||||||
|  |  | ||||||
| 	if err := m.switchToGpsMode(); err != nil { |  | ||||||
| 		return fmt.Errorf("switch to GPS: %w", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if err := m.Update(); err != nil { | 	if err := m.Update(); err != nil { | ||||||
| 		return fmt.Errorf("update: %w", err) | 		return fmt.Errorf("update: %w", err) | ||||||
| 	} | 	} | ||||||
| @@ -198,7 +239,6 @@ func (m *modem) saveGPS(path string) error { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("open file: %w", err) | 		return fmt.Errorf("open file: %w", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	defer f.Close() | 	defer f.Close() | ||||||
|  |  | ||||||
| 	if _, err = f.WriteString(m.getShortInfo()); err != nil { | 	if _, err = f.WriteString(m.getShortInfo()); err != nil { | ||||||
| @@ -207,6 +247,22 @@ func (m *modem) saveGPS(path string) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (m *modem) testConsole() { | ||||||
|  | 	for { | ||||||
|  | 		var inStr string | ||||||
|  | 		fmt.Scanln(&inStr) | ||||||
|  | 		if inStr == "exit" { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		resp, err := m.port.Send(inStr) | ||||||
|  | 		if err != nil { | ||||||
|  | 			m.logger.Println("ERROR:", err.Error()) | ||||||
|  | 		} | ||||||
|  | 		m.logger.Println(resp) | ||||||
|  | 		m.logger.Println("------------------") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| func (m *modem) checkPort(portName string) (outErr error) { | func (m *modem) checkPort(portName string) (outErr error) { | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		if outErr != nil { // Clear port if there is error | 		if outErr != nil { // Clear port if there is error | ||||||
| @@ -227,16 +283,26 @@ func (m *modem) checkPort(portName string) (outErr error) { | |||||||
| 	} | 	} | ||||||
| 	defer m.port.Disconnect() // Do not bother about errors... | 	defer m.port.Disconnect() // Do not bother about errors... | ||||||
|  |  | ||||||
|  | 	// Reset input | ||||||
|  | 	if err := m.port.GetSerialPort().ResetInputBuffer(); err != nil { | ||||||
|  | 		return fmt.Errorf("reset input buffer: %w", err) | ||||||
|  | 	} | ||||||
|  | 	// Reset output | ||||||
|  | 	if err := m.port.GetSerialPort().ResetOutputBuffer(); err != nil { | ||||||
|  | 		return fmt.Errorf("reset output buffer: %w", err) | ||||||
|  | 	} | ||||||
|  | 	m.port.Send("ATE0") // This shit sometimes enables echo mode... why... when... but it can | ||||||
|  | 	// m.port.Send("\r\n") | ||||||
|  |  | ||||||
| 	// Ping | 	// Ping | ||||||
| 	m.logger.Println("Ping...") | 	m.logger.Println("Ping...") | ||||||
|  |  | ||||||
| 	if err := m.ping(); err != nil { | 	if err := m.ping(); err != nil { | ||||||
| 		return fmt.Errorf("ping error: %w", err) | 		return fmt.Errorf("ping error: %w", err) | ||||||
| 	} | 	} | ||||||
|  | 	m.logger.Println("\x1b[38;2;0;255;0mOK\x1b[38;2;255;255;255m") | ||||||
|  |  | ||||||
| 	// Check model | 	// Check model | ||||||
| 	m.logger.Println("Check model...") | 	m.logger.Println("Check model...") | ||||||
|  |  | ||||||
| 	resp, err := m.port.Send("AT+CGMM") | 	resp, err := m.port.Send("AT+CGMM") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("get model: %w", err) | 		return fmt.Errorf("get model: %w", err) | ||||||
| @@ -250,10 +316,10 @@ func (m *modem) checkPort(portName string) (outErr error) { | |||||||
| 	} | 	} | ||||||
| 	rightModel := "SIMCOM_SIM7600E-H" | 	rightModel := "SIMCOM_SIM7600E-H" | ||||||
| 	// m.logger.Printf("[% x]\n [% x]", []byte("SIMCOM_SIM7600E-H"), []byte(model)) | 	// m.logger.Printf("[% x]\n [% x]", []byte("SIMCOM_SIM7600E-H"), []byte(model)) | ||||||
| 	if model[:len(rightModel)] != rightModel { | 	if len(model) >= len(rightModel) && model[:len(rightModel)] != rightModel { | ||||||
| 		return fmt.Errorf("invalid modem model: %s", model) | 		return fmt.Errorf("invalid modem model: %s", model) | ||||||
| 	} | 	} | ||||||
| 	m.logger.Println("Model right") | 	m.logger.Println("\x1b[38;2;0;255;0mOK\x1b[38;2;255;255;255m") | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -274,7 +340,7 @@ SearchLoop: | |||||||
| 		m.logger.Printf("Checking port %s ...\n", p) | 		m.logger.Printf("Checking port %s ...\n", p) | ||||||
|  |  | ||||||
| 		if err := m.checkPort("/dev/" + p); err != nil { | 		if err := m.checkPort("/dev/" + p); err != nil { | ||||||
| 			m.logger.Printf("Check failed: %s\n", err.Error()) | 			m.logger.Printf("\x1b[38;2;255;0;0mCheck failed: %s\x1b[38;2;255;255;255m\n", err.Error()) | ||||||
| 			continue SearchLoop | 			continue SearchLoop | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -296,40 +362,6 @@ func (m *modem) ping() error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *modem) switchToGpsMode() error { |  | ||||||
| 	m.logger.Println("Enabling GPS mode...") |  | ||||||
| 	// Reset intput |  | ||||||
| 	if err := m.port.GetSerialPort().ResetInputBuffer(); err != nil { |  | ||||||
| 		return fmt.Errorf("reset input buffer: %w", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Check gps mode status |  | ||||||
| 	resp, err := m.port.Send("AT+CGPS?") |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("make at ask: %w", err) |  | ||||||
| 	} |  | ||||||
| 	if !resp.Check() { |  | ||||||
| 		return fmt.Errorf("error response") |  | ||||||
| 	} |  | ||||||
| 	ans := strings.Replace(strings.Split(strings.Split(resp.RmFront("+CGPS:").String(), "\n")[0], ",")[0], " ", "", -1) |  | ||||||
| 	if ans == "1" { |  | ||||||
| 		m.logger.Println("GPS already enabled") |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 	m.logger.Println(ans) |  | ||||||
|  |  | ||||||
| 	// Modem is not in GPS mode |  | ||||||
| 	resp, err = m.port.Send("AT+CGPS=1") |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("try to switch to gps: %w", err) |  | ||||||
| 	} |  | ||||||
| 	if !resp.Check() { |  | ||||||
| 		return fmt.Errorf("switch tp GPS failed") |  | ||||||
| 	} |  | ||||||
| 	m.logger.Println("GPS mode enabled") |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func getTtyDevices() ([]string, error) { | func getTtyDevices() ([]string, error) { | ||||||
| 	// Get ports | 	// Get ports | ||||||
| 	/**/ | 	/**/ | ||||||
|   | |||||||
							
								
								
									
										69
									
								
								api/modem/sms/errors.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								api/modem/sms/errors.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  | package sms | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"strconv" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func DecodeError(code int) string { | ||||||
|  | 	switch code { | ||||||
|  | 	case 300: | ||||||
|  | 		return "ME failure" | ||||||
|  | 	case 301: | ||||||
|  | 		return "SMS service of ME reserved" | ||||||
|  | 	case 302: | ||||||
|  | 		return "Operation not allowed" | ||||||
|  | 	case 303: | ||||||
|  | 		return "Operation not supported" | ||||||
|  | 	case 304: | ||||||
|  | 		return "Invalid PDU mode parameter" | ||||||
|  | 	case 305: | ||||||
|  | 		return "Invalid text mode parameter" | ||||||
|  | 	case 310: | ||||||
|  | 		return "SIM not inserted" | ||||||
|  | 	case 311: | ||||||
|  | 		return "SIM PIN required" | ||||||
|  | 	case 312: | ||||||
|  | 		return "PH-SIM PIN required" | ||||||
|  | 	case 313: | ||||||
|  | 		return "SIM failure" | ||||||
|  | 	case 314: | ||||||
|  | 		return "SIM busy" | ||||||
|  | 	case 315: | ||||||
|  | 		return "SIM wrong" | ||||||
|  | 	case 316: | ||||||
|  | 		return "SIM PUK required" | ||||||
|  | 	case 317: | ||||||
|  | 		return "SIM PIN2 required" | ||||||
|  | 	case 318: | ||||||
|  | 		return "SIM PUK2 required" | ||||||
|  | 	case 320: | ||||||
|  | 		return "Memory failure" | ||||||
|  | 	case 321: | ||||||
|  | 		return "Invalid memory index" | ||||||
|  | 	case 322: | ||||||
|  | 		return "Memory full" | ||||||
|  | 	case 330: | ||||||
|  | 		return "SMSC address unknown" | ||||||
|  | 	case 331: | ||||||
|  | 		return "No network service" | ||||||
|  | 	case 332: | ||||||
|  | 		return "Network timeout" | ||||||
|  | 	case 340: | ||||||
|  | 		return "NO +CNMA ACK EXPECTED" | ||||||
|  | 	case 341: | ||||||
|  | 		return "Buffer overflow" | ||||||
|  | 	case 342: | ||||||
|  | 		return "SMS size more than expected" | ||||||
|  | 	case 500: | ||||||
|  | 		return "Unknown error" | ||||||
|  | 	} | ||||||
|  | 	return "UNDEFINED ERROR CODE" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func GetError(msg []byte) (int, error) { | ||||||
|  | 	if len(msg) >= len("+CMS ERROR: ")+3 && string(msg[:len("+CMS ERROR: ")]) == "+CMS ERROR: " { | ||||||
|  | 		return strconv.Atoi(string(msg[len("+CMS ERROR: ") : len("+CMS ERROR: ")+3])) | ||||||
|  | 	} | ||||||
|  | 	return 0, fmt.Errorf("failed to parse error") | ||||||
|  | } | ||||||
							
								
								
									
										85
									
								
								api/modem/sms/sms.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								api/modem/sms/sms.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | |||||||
|  | package sms | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"log" | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
|  | 	"github.com/CGSG-2021-AE4/modem-test/api/modem/at" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type dialer struct { | ||||||
|  | 	logger *log.Logger | ||||||
|  | 	port   at.Port | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type Dialer interface { | ||||||
|  | 	Init() error | ||||||
|  | 	Send(number, msg string) error | ||||||
|  | 	ReadNew() ([]string, error) | ||||||
|  | 	io.Closer | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func New(logger *log.Logger, port at.Port) Dialer { | ||||||
|  | 	return &dialer{ | ||||||
|  | 		logger: logger, | ||||||
|  | 		port:   port, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *dialer) Init() error { | ||||||
|  | 	// Ensure serial port | ||||||
|  | 	if !d.port.IsConnected() { | ||||||
|  | 		return fmt.Errorf("serial port is not connected") | ||||||
|  | 	} | ||||||
|  | 	// Ensure text format | ||||||
|  | 	if resp, err := d.port.Send("AT+CMGF=1"); err != nil || !resp.Check() { | ||||||
|  | 		if err != nil { | ||||||
|  | 			return fmt.Errorf("AT+CMGF=1 request: %w", err) | ||||||
|  | 		} | ||||||
|  | 		return fmt.Errorf("failed to set SMS format") | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *dialer) Send(number, msg string) error { | ||||||
|  | 	d.port.Send(fmt.Sprintf("AT+CMGS=\"%s\"", number))      // Because it will throw error | ||||||
|  | 	resp, err := d.port.RawSend(fmt.Sprintf("%s\x1A", msg)) // Add additional \r\n because there is not supposed to be | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("message request: %w", err) | ||||||
|  | 	} | ||||||
|  | 	if at.Resp(resp).Check() { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	errCode, err := GetError([]byte(resp)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("send sms failed and failed to get error: %w", err) | ||||||
|  | 	} | ||||||
|  | 	return fmt.Errorf("failed to send with SMS error: %d - %s", errCode, DecodeError(errCode)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Reads all new messages | ||||||
|  | func (d *dialer) ReadNew() ([]string, error) { | ||||||
|  | 	resp, err := d.port.Send("AT+CMGL") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("AT+CMGL request: %w", err) | ||||||
|  | 	} | ||||||
|  | 	msgs := strings.Split(strings.Replace(string(resp), "\r", "", -1), "\n") | ||||||
|  |  | ||||||
|  | 	outMsgs := make([]string, 0) | ||||||
|  | 	for _, s := range msgs { | ||||||
|  | 		if len(s) >= len("+CMGL:") && s[:len("+CMGL:")] == "+CMGL:" { | ||||||
|  | 			params := strings.Split(s[len("+CMGL:"):], ",") | ||||||
|  | 			d.logger.Println("GET MSG:", params) | ||||||
|  | 		} else { | ||||||
|  | 			outMsgs = append(outMsgs, s) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return outMsgs, nil // TODO | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *dialer) Close() error { | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								main.go
									
									
									
									
									
								
							| @@ -17,14 +17,27 @@ func main() { | |||||||
|  |  | ||||||
| func mainE() error { | func mainE() error { | ||||||
| 	m := modem.New(log.New(os.Stdout, "modem:", log.LstdFlags)) | 	m := modem.New(log.New(os.Stdout, "modem:", log.LstdFlags)) | ||||||
|  | 	log.Println("||||||||||||||||| INIT |||||||||||||||") | ||||||
| 	if err := m.Init(); err != nil { | 	if err := m.Init(); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  | 	if !m.Validate() { | ||||||
|  | 		log.Println("AAAAAAAAAAAAAAA Validation failed") | ||||||
| 		return nil | 		return nil | ||||||
| 	// ports, err := serial.GetPortsList() | 	} | ||||||
| 	// if err != nil { | 	log.Println("||||||||||||||||| GET INFO |||||||||||||||||") | ||||||
|  | 	log.Println(m.GetInfo()) | ||||||
|  |  | ||||||
|  | 	log.Println("||||||||||||||||| SEND SMS |||||||||||||||||") | ||||||
|  | 	log.Println(m.At().Send("AT+CNUM")) | ||||||
|  | 	// if err := m.Sms().Send("+79218937173", "CGSG forever"); err != nil { | ||||||
| 	// 	return err | 	// 	return err | ||||||
| 	// } | 	// } | ||||||
| 	// log.Println(ports) | 	if ms, err := m.Sms().ReadNew(); err != nil { | ||||||
| 	// return nil | 		return err | ||||||
|  | 	} else { | ||||||
|  | 		log.Println("NEW:", ms) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user