Improved SMS.
This commit is contained in:
parent
b3fb13b7b3
commit
75d05f197c
@ -116,23 +116,33 @@ func (p *atPort) RawSend(msg string) (string, error) {
|
||||
}
|
||||
// time.Sleep(time.Millisecond)
|
||||
// Read
|
||||
readLen, err := p.port.Read(p.inputBuf)
|
||||
// p.logger.Println(msg, "\x1b[38;2;150;150;150mRAWREAD:", string(p.inputBuf[:readLen]), "\x1b[38;2;255;255;255m")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("port read: %w", err)
|
||||
outBuf := make([]byte, 0)
|
||||
readLoop:
|
||||
for {
|
||||
readLen, err := p.port.Read(p.inputBuf)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("port read: %w", err)
|
||||
}
|
||||
if readLen == 0 {
|
||||
break readLoop
|
||||
}
|
||||
outBuf = append(outBuf, p.inputBuf[:readLen]...)
|
||||
if readLen < len(p.inputBuf) {
|
||||
break readLoop
|
||||
}
|
||||
}
|
||||
// p.logger.Println(msg, "\x1b[38;2;150;150;150mRAWREAD:", string(p.inputBuf[:readLen]), "\x1b[38;2;255;255;255m")
|
||||
|
||||
return string(p.inputBuf[:readLen]), nil
|
||||
return string(outBuf), nil
|
||||
}
|
||||
|
||||
func (p *atPort) Send(cmd string) (Resp, error) {
|
||||
cmd += "\r\n"
|
||||
rawResp, err := p.RawSend(cmd)
|
||||
rawResp, err := p.RawSend(cmd + "\r\n")
|
||||
if err != nil {
|
||||
return RespNil, fmt.Errorf("make request: %w", err)
|
||||
return RespNil, fmt.Errorf("%s request: %w", cmd, err)
|
||||
}
|
||||
if len(rawResp) <= 4 {
|
||||
return RespNil, fmt.Errorf("read too small msg: %d byte - %s", len(rawResp), string(rawResp))
|
||||
return RespNil, fmt.Errorf("%s request: read too small msg: %d byte - %s", cmd, len(rawResp), string(rawResp))
|
||||
}
|
||||
resp := rawResp[2 : len(rawResp)-2] // Cut \r\n
|
||||
|
||||
|
@ -85,7 +85,7 @@ func (g *gps) switchGpsMode(on bool) error {
|
||||
// Check gps mode status
|
||||
resp, err := g.port.Send("AT+CGPS?")
|
||||
if err != nil {
|
||||
return fmt.Errorf("make at ask: %w", err)
|
||||
return err
|
||||
}
|
||||
if !resp.Check() || !resp.CheckFront("+CGPS:") {
|
||||
return fmt.Errorf("get GPS mode: error response: %s", resp)
|
||||
@ -98,7 +98,7 @@ func (g *gps) switchGpsMode(on bool) error {
|
||||
// Modem is not in GPS mode
|
||||
resp, err = g.port.Send("AT+CGPS=" + onStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("set GPS mode: %w", err)
|
||||
return err
|
||||
}
|
||||
if !resp.Check() {
|
||||
return fmt.Errorf("set GPS mode: error response: %s", resp)
|
||||
|
@ -56,7 +56,7 @@ func (g *gps) rawCollect(flags nmeaFlags) (string, error) {
|
||||
|
||||
// Set output rate to 10Hz
|
||||
if resp, err := g.port.Send("AT+CGPSNMEARATE=1"); err != nil {
|
||||
return "", fmt.Errorf("AT+CGPSNMEARATE= request: %w", err)
|
||||
return "", err
|
||||
} else {
|
||||
if !resp.Check() {
|
||||
return "", fmt.Errorf("set output rate: error response: %s", resp)
|
||||
|
@ -112,19 +112,19 @@ func (m *modem) Init() error {
|
||||
// submodulesLogger := io.Discard // FOR less logs
|
||||
|
||||
m.logger.Println("=============================== Init submodules")
|
||||
//m.ic = internet.New(log.New(submodulesLogger, "modem-internet : ", log.LstdFlags), m.port)
|
||||
//if err := m.ic.Init(); err != nil {
|
||||
// m.logger.Printf("\x1b[38;2;255;0;0mInternet: %s\x1b[38;2;255;255;255m\n", err.Error())
|
||||
//} else {
|
||||
// m.logger.Println("\x1b[38;2;0;255;0mInternet 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.ic = internet.New(log.New(submodulesLogger, "modem-internet : ", log.LstdFlags), m.port)
|
||||
// if err := m.ic.Init(); err != nil {
|
||||
// m.logger.Printf("\x1b[38;2;255;0;0mInternet: %s\x1b[38;2;255;255;255m\n", err.Error())
|
||||
// } else {
|
||||
// m.logger.Println("\x1b[38;2;0;255;0mInternet 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 {
|
||||
@ -180,6 +180,13 @@ func (m *modem) PowerOff() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *modem) restart() error {
|
||||
m.PowerOff()
|
||||
time.Sleep(10 * time.Second)
|
||||
m.PowerOn()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *modem) Sms() sms.Sms {
|
||||
return m.sms
|
||||
}
|
||||
@ -272,7 +279,7 @@ func (m *modem) printCmd(cmd string) {
|
||||
m.logger.Println("FAILED TO SEND REQ", cmd, ":", err.Error())
|
||||
} else {
|
||||
_ = resp
|
||||
// m.logger.Println("CMD", cmd, ":", resp)
|
||||
m.logger.Println("CMD", cmd, ":", resp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,7 +294,9 @@ func (m *modem) setupPort() error {
|
||||
return fmt.Errorf("reset output buffer: %w", err)
|
||||
}
|
||||
|
||||
// m.restart()
|
||||
// These commands ensure that correct modes are set
|
||||
// m.port.RawSend("\r\n\x1A\r\n") // Sometimes enables echo mode
|
||||
m.printCmd("ATE0") // Sometimes enables echo mode
|
||||
m.printCmd("AT+CGPSFTM=0") // Sometimes does not turn off nmea
|
||||
m.printCmd("AT+CMEE=2") // Turn on errors describtion
|
||||
@ -315,8 +324,10 @@ func (m *modem) checkPort(portName string) (outErr error) {
|
||||
}
|
||||
defer m.port.Disconnect() // Do not bother about errors...
|
||||
|
||||
// m.restart()
|
||||
|
||||
// To filter dead ports
|
||||
if _, err := m.port.Send("AT"); err != nil {
|
||||
if str, err := m.port.RawSend("AT"); err != nil || len(str) == 0 {
|
||||
return fmt.Errorf("ping error: %w", err)
|
||||
}
|
||||
|
||||
|
@ -1,69 +0,0 @@
|
||||
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")
|
||||
}
|
105
api/modem/sms/setup.go
Normal file
105
api/modem/sms/setup.go
Normal file
@ -0,0 +1,105 @@
|
||||
package sms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"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
|
||||
// 1: read and delete
|
||||
// 2: sending
|
||||
// 3: write received
|
||||
|
||||
// First try SM
|
||||
if _, err := d.port.Send(`AT+CPMS="SM","SM","SM"`); err != nil {
|
||||
return fmt.Errorf(`AT+CPMS="SM","SM","SM" request: %w`, err)
|
||||
}
|
||||
st, err := d.getCurMsgStSize()
|
||||
if err != nil {
|
||||
return fmt.Errorf("SM: %w", err)
|
||||
}
|
||||
if st[0].Used < st[0].Total {
|
||||
d.logger.Printf("Use SM message storage: %d/%d\n", st[0].Used, st[0].Total)
|
||||
return nil // There is space
|
||||
}
|
||||
d.logger.Printf("SM message storage is full: %d/%d\n", st[0].Used, st[0].Total)
|
||||
|
||||
// Second try ME
|
||||
if _, err := d.port.Send(`AT+CPMS="ME","ME","ME"`); err != nil {
|
||||
return fmt.Errorf(`AT+CPMS="ME","ME","ME" request: %w`, err)
|
||||
}
|
||||
st, err = d.getCurMsgStSize()
|
||||
if err != nil {
|
||||
return fmt.Errorf("ME: %w", err)
|
||||
}
|
||||
if st[0].Used < st[0].Total {
|
||||
d.logger.Printf("Use ME message storage: %d/%d\n", st[0].Used, st[0].Total)
|
||||
return nil // There is space
|
||||
}
|
||||
d.logger.Printf("ME message storage is full: %d/%d\n", st[0].Used, st[0].Total)
|
||||
// Otherwise error
|
||||
return fmt.Errorf("all storages are full")
|
||||
}
|
||||
|
||||
// Message storage
|
||||
type msgSt struct {
|
||||
Name string
|
||||
Used int
|
||||
Total int
|
||||
}
|
||||
|
||||
// Get size of used and total mem of current memory storage
|
||||
func (d *dialer) getCurMsgStSize() ([]msgSt, error) {
|
||||
// Request
|
||||
resp, err := d.port.Send("AT+CPMS?")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("AT+CPMS? request: %w", err)
|
||||
}
|
||||
// Check start and end
|
||||
if !resp.Check() && !resp.CheckFront("+CPMS:") {
|
||||
return nil, fmt.Errorf("AT+CPMS")
|
||||
}
|
||||
// Remove front and cut to values
|
||||
resp = resp.RmFront("+CPMS:")
|
||||
values := strings.Split(strings.ReplaceAll(strings.Split(resp.String(), "\n")[0], "\r", ""), ",")
|
||||
if len(values) != 9 {
|
||||
return nil, fmt.Errorf("CPMS response: invalid values count: [%s]", values)
|
||||
}
|
||||
|
||||
// Parse values
|
||||
outMsgs := [3]msgSt{}
|
||||
for i := 0; i < 3; i++ {
|
||||
name := values[i]
|
||||
used, err := strconv.Atoi(values[i*3+1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse value #%d: %w", i+1, err)
|
||||
}
|
||||
total, err := strconv.Atoi(values[i*3+2])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse value #%d, %w", i+2, err)
|
||||
}
|
||||
|
||||
outMsgs[i] = msgSt{name, used, total}
|
||||
}
|
||||
return outMsgs[:], nil
|
||||
}
|
@ -30,55 +30,51 @@ func New(logger *log.Logger, port at.Port) Sms {
|
||||
}
|
||||
|
||||
func (d *dialer) Init() error {
|
||||
// Ensure serial port
|
||||
// Ensure serial port is connected
|
||||
if !d.port.IsConnected() {
|
||||
return fmt.Errorf("serial port is not connected")
|
||||
}
|
||||
|
||||
// Check SIM an PIN
|
||||
if resp, err := d.port.Send("AT+CPIN?"); err != nil || !resp.Check() {
|
||||
if err != nil {
|
||||
return fmt.Errorf("check pin: %w", err)
|
||||
}
|
||||
return fmt.Errorf("check pin: error response: %s", resp)
|
||||
// Check ping
|
||||
if err := d.checkPIN(); err != nil {
|
||||
return fmt.Errorf("check PIN: %w", err)
|
||||
}
|
||||
|
||||
// Ensure text format
|
||||
d.logger.Println(d.port.Send("AT+CMGF"))
|
||||
if resp, err := d.port.Send("AT+CMGF=1"); err != nil || !resp.Check() {
|
||||
// Setup prefered message storage
|
||||
if err := d.setupMsgSt(); err != nil {
|
||||
return fmt.Errorf("setup msg storage: %w", err)
|
||||
}
|
||||
// Check number
|
||||
if resp, err := d.port.Send("AT+CNUM"); err != nil || !resp.Check() {
|
||||
if err != nil {
|
||||
return fmt.Errorf("set to text format request: %w", err)
|
||||
return fmt.Errorf("AT+CNUM request ")
|
||||
}
|
||||
return fmt.Errorf("set SIM format: error response: %s", resp)
|
||||
}
|
||||
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\n\r", msg)) // Add additional \r\n because there is not supposed to be
|
||||
sresp, err := d.port.Send(fmt.Sprintf(`AT+CMGSEX="%s"`, number)) // Because it will throw error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.logger.Println(sresp)
|
||||
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)
|
||||
}
|
||||
d.logger.Println("SEND RESPONSE:", resp)
|
||||
resp, err = d.port.RawSend("\x1A")
|
||||
if err != nil {
|
||||
return fmt.Errorf("message request: %w", err)
|
||||
d.logger.Println("Send response:", resp)
|
||||
if !at.Resp(resp).Check() {
|
||||
return fmt.Errorf("error response: %s", resp)
|
||||
}
|
||||
d.logger.Println("SEND RESPONSE:", resp)
|
||||
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))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reads all new messages
|
||||
func (d *dialer) ReadNew() ([]string, error) {
|
||||
resp, err := d.port.Send("AT+CMGL=\"UNREAD\"")
|
||||
resp, err := d.port.Send("AT+CMGL=\"ALL\"")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("AT+CMGL request: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
d.logger.Println("raw sms:", resp)
|
||||
msgs := strings.Split(strings.Replace(string(resp), "\r", "", -1), "\n")
|
||||
|
||||
outMsgs := make([]string, 0)
|
||||
|
91
main.go
91
main.go
@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
|
||||
"gitea.unprism.ru/KRBL/sim-modem/api/modem"
|
||||
"gitea.unprism.ru/KRBL/sim-modem/api/modem/at"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -35,16 +36,14 @@ func mainE() error {
|
||||
logger.Println("AAAAAAAAAAAAAAA Modem is not connected")
|
||||
return nil
|
||||
}
|
||||
// m.PowerOff()
|
||||
// time.Sleep(10 * time.Second)
|
||||
// m.PowerOn()
|
||||
|
||||
logger.Println("||||||||||||||||| GET INFO |||||||||||||||||")
|
||||
logger.Println(m.Update())
|
||||
logger.Printf("DATA: %+v\n", m.GetData())
|
||||
// logger.Println("||||||||||||||||| GET INFO |||||||||||||||||")
|
||||
// logger.Println(m.Update())
|
||||
// logger.Printf("DATA: %+v\n", m.GetData())
|
||||
|
||||
// logger.Println("||||||||||||||||| SEND SMS |||||||||||||||||")
|
||||
// logger.Println(m.At().Send("AT+CNUM"))
|
||||
logger.Println("||||||||||||||||| SMS |||||||||||||||||")
|
||||
// resp, err := m.At().Send("AT+CNUM")
|
||||
// logger.Println("CNUM:", resp, err)
|
||||
// // if err := m.Sms().Send("+79218937173", "CGSG forever"); err != nil {
|
||||
// // return err
|
||||
// // }
|
||||
@ -53,12 +52,78 @@ func mainE() error {
|
||||
// } else {
|
||||
// logger.Println("NEW:", ms)
|
||||
// }
|
||||
logger.Println("||||||||||||||||| Checking gps status |||||||||||||||||")
|
||||
st, err := m.Gps().GetStatus()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Cmd := func(cmd string) {
|
||||
resp, err := m.At().Send(cmd)
|
||||
logger.Println(cmd, "===>", resp, err)
|
||||
}
|
||||
logger.Printf("GPS Status:%+v\n", st)
|
||||
_ = Cmd
|
||||
|
||||
var resp at.Resp
|
||||
var err error
|
||||
buf := make([]byte, 256)
|
||||
_ = resp
|
||||
_ = err
|
||||
_ = buf
|
||||
|
||||
// Select ME PMS
|
||||
// resp, err = m.At().Send("AT+CPMS=?")
|
||||
// logger.Println("Possible mem storages:", resp, err)
|
||||
// resp, err = m.At().Send("AT+CPMS?")
|
||||
// logger.Println("Prefered mem storage:", resp, err)
|
||||
// Cmd("AT")
|
||||
// logger.Println("SEND SMS")
|
||||
// logger.Println(m.Sms().Send("+79218937173", "CGSG forever!!!"))
|
||||
// m.At().RawSend("\r\n\x1A\r\n")
|
||||
|
||||
for {
|
||||
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?")
|
||||
// logger.Println("Prefered mem storage:", resp, err)
|
||||
|
||||
// resp, err = m.At().Send("AT+CREG?")
|
||||
// logger.Println("Network registration:", resp, err)
|
||||
// resp, err = m.At().Send("AT+CPMS?")
|
||||
// logger.Println("Prefered mem storage:", resp, err)
|
||||
// resp, err = m.At().Send("AT+CPMS=?")
|
||||
// logger.Println("Possible mem storage:", resp, err)
|
||||
// resp, err = m.At().Send("AT+CNMI?")
|
||||
// logger.Println("New message indications:", resp, err)
|
||||
// resp, err = m.At().Send("AT+CMGL=\"REC UNREAD\"")
|
||||
// logger.Println("New messages:", resp, err)
|
||||
// resp, err = m.At().Send("AT+CNMI=2,1")
|
||||
// logger.Println("AT+CNMI=2,1:", resp, err)
|
||||
// resp, err = m.At().Send("AT+CNMI?")
|
||||
// logger.Println("New message indications:", resp, err)
|
||||
// logger.Println("Reading port...")
|
||||
// for {
|
||||
// readLen, err := m.At().SerialPort().Read(buf)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// if readLen > 0 {
|
||||
// logger.Println(string(buf[:readLen]))
|
||||
// }
|
||||
// }
|
||||
// for {
|
||||
// resp, err = m.At().Send("AT+CSQ")
|
||||
// logger.Println("AT+CSQ:", resp, err)
|
||||
// time.Sleep(500 * time.Millisecond)
|
||||
// }
|
||||
// logger.Println("||||||||||||||||| Checking gps status |||||||||||||||||")
|
||||
// st, err := m.Gps().GetStatus()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// logger.Printf("GPS Status:%+v\n", st)
|
||||
|
||||
// logger.Println("Turn off", m.PowerOff())
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user