Added signal check.

This commit is contained in:
Andrey Egorov 2024-08-10 15:21:27 +03:00
parent 75d05f197c
commit d21ad0ce00
5 changed files with 169 additions and 28 deletions

View File

@ -37,8 +37,9 @@ type Port interface {
Disconnect() error Disconnect() error
IsConnected() bool IsConnected() bool
RawSend(msg string) (string, error) RawSend(msg string, timeout time.Duration) (string, error)
Send(cmd string) (Resp, error) Send(cmd string) (Resp, error)
SendWithTimeout(cmd string, timeout time.Duration) (Resp, error)
io.Closer io.Closer
} }
@ -106,7 +107,7 @@ func (p *atPort) IsConnected() bool {
} }
// Low level write/read function // Low level write/read function
func (p *atPort) RawSend(msg string) (string, error) { func (p *atPort) RawSend(msg string, timeout time.Duration) (string, error) {
p.mutex.Lock() p.mutex.Lock()
defer p.mutex.Unlock() defer p.mutex.Unlock()
@ -114,7 +115,7 @@ func (p *atPort) RawSend(msg string) (string, error) {
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) time.Sleep(timeout)
// Read // Read
outBuf := make([]byte, 0) outBuf := make([]byte, 0)
readLoop: readLoop:
@ -131,13 +132,26 @@ readLoop:
break readLoop break readLoop
} }
} }
// p.logger.Println(msg, "\x1b[38;2;150;150;150mRAWREAD:", string(p.inputBuf[:readLen]), "\x1b[38;2;255;255;255m") // p.logger.Println(msg, "\x1b[38;2;150;150;150mRAWREAD:", string(outBuf), "\x1b[38;2;255;255;255m")
return string(outBuf), nil return string(outBuf), nil
} }
func (p *atPort) Send(cmd string) (Resp, error) { func (p *atPort) Send(cmd string) (Resp, error) {
rawResp, err := p.RawSend(cmd + "\r\n") rawResp, err := p.RawSend(cmd+"\r\n", time.Microsecond)
if err != nil {
return RespNil, fmt.Errorf("%s request: %w", cmd, err)
}
if len(rawResp) <= 4 {
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
return Resp(resp), nil
}
func (p *atPort) SendWithTimeout(cmd string, timeout time.Duration) (Resp, error) {
rawResp, err := p.RawSend(cmd+"\r\n", timeout)
if err != nil { if err != nil {
return RespNil, fmt.Errorf("%s request: %w", cmd, err) return RespNil, fmt.Errorf("%s request: %w", cmd, err)
} }

View File

@ -15,6 +15,7 @@ import (
"gitea.unprism.ru/KRBL/sim-modem/api/modem/gps" "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/internet"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/sms" "gitea.unprism.ru/KRBL/sim-modem/api/modem/sms"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/utils"
) )
type ModemData struct { type ModemData struct {
@ -53,6 +54,7 @@ type Modem interface {
IsConnected() bool IsConnected() bool
Update() error Update() error
GetData() ModemData GetData() ModemData
CheckSignal() error
PowerOn() error PowerOn() error
PowerOff() error PowerOff() error
@ -170,6 +172,10 @@ func (m *modem) GetData() ModemData {
} }
} }
func (m *modem) CheckSignal() error {
return utils.CheckSignal(m.port, m.logger)
}
func (m *modem) PowerOn() error { func (m *modem) PowerOn() error {
m.onOffPin.PowerOn() // DEBUG do not want to wait 30 seconds m.onOffPin.PowerOn() // DEBUG do not want to wait 30 seconds
return nil return nil
@ -276,10 +282,10 @@ func (m *modem) saveGPS(path string) error {
// Short way to send command // Short way to send command
func (m *modem) printCmd(cmd string) { func (m *modem) printCmd(cmd string) {
if resp, err := m.port.Send(cmd); err != nil { if resp, err := m.port.Send(cmd); err != nil {
m.logger.Println("FAILED TO SEND REQ", cmd, ":", err.Error()) m.logger.Println("FAILED TO SEND REQ", cmd, "===>", err.Error())
} else { } else {
_ = resp _ = resp
m.logger.Println("CMD", cmd, ":", resp) // m.logger.Println("CMD", cmd, "===>", resp)
} }
} }
@ -304,6 +310,16 @@ func (m *modem) setupPort() error {
return nil return nil
} }
func (m *modem) checkCurPortDead() error {
if resp, err := m.port.RawSend("AT\r\n", 20*time.Millisecond); err != nil || len(resp) == 0 {
if err != nil {
return fmt.Errorf("raw send: %w", err)
}
return fmt.Errorf("read 0")
}
return nil
}
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
@ -327,8 +343,9 @@ func (m *modem) checkPort(portName string) (outErr error) {
// m.restart() // m.restart()
// To filter dead ports // To filter dead ports
if str, err := m.port.RawSend("AT"); err != nil || len(str) == 0 {
return fmt.Errorf("ping error: %w", err) if err := m.checkCurPortDead(); err != nil {
return fmt.Errorf("echo: %w", err)
} }
if err := m.setupPort(); err != nil { if err := m.setupPort(); err != nil {

View File

@ -5,6 +5,7 @@ import (
"io" "io"
"log" "log"
"strings" "strings"
"time"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/at" "gitea.unprism.ru/KRBL/sim-modem/api/modem/at"
) )
@ -40,7 +41,7 @@ func (d *dialer) Init() error {
} }
// Setup prefered message storage // Setup prefered message storage
if err := d.setupMsgSt(); err != nil { if err := d.setupMsgSt(); err != nil {
return fmt.Errorf("setup msg storage: %w", err) d.logger.Printf("ERROR setup msg storage: %s\n", err.Error())
} }
// Check number // Check number
if resp, err := d.port.Send("AT+CNUM"); err != nil || !resp.Check() { if resp, err := d.port.Send("AT+CNUM"); err != nil || !resp.Check() {
@ -57,7 +58,7 @@ func (d *dialer) Send(number, msg string) error {
return err return err
} }
d.logger.Println(sresp) 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 resp, err := d.port.RawSend(fmt.Sprintf("%s\x1A", msg), time.Millisecond) // Add additional \r\n because there is not supposed to be
if err != nil { if err != nil {
return fmt.Errorf("message request: %w", err) return fmt.Errorf("message request: %w", err)
} }

108
api/modem/utils/signal.go Normal file
View File

@ -0,0 +1,108 @@
package utils
import (
"fmt"
"log"
"strconv"
"strings"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/at"
)
func CheckSignal(port at.Port, logger *log.Logger) error {
rssi, ber, err := getSignalQuality(port)
if err != nil {
return 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)
}
if err := checkBer(ber); err != nil {
logger.Printf("bad ber(not critical): %s", err.Error()) // Happened not to be critical
}
return nil
}
func checkRssi(rssi int) error {
// rssi - Received signal strenght indicator
// 0 -113 dBm or less
// 1 -111 dBm
// 2...30 -109... - 53 dBm
// 31 -51 dBm or greater
// 99 not known or not detectable
// 100 -116 dBm or less
// 101 -115 dBm
// 102…191 -114... - 26dBm
// 191 -25 dBm or greater
// 199 not known or not detectable
// 100…199 expand to TDSCDMA, indicate RSCPreceived
if rssi <= 2 { // Too poor
return fmt.Errorf("too poor <= -109dBm")
}
if rssi > 2 && rssi <= 31 {
return nil // Can live
}
if rssi == 99 {
return fmt.Errorf("not known or not detectable")
}
if rssi >= 100 && rssi <= 102 {
return fmt.Errorf("too poor <= -114dBm")
}
if rssi > 102 && rssi <= 191 {
return nil // Can live
}
if rssi == 199 {
return fmt.Errorf("not known or not detectable")
}
return fmt.Errorf("invalid code %d", rssi)
}
func checkBer(ber int) error {
// ber - Bit error rate
// 0 <0.01%
// 1 0.01% --- 0.1%
// 2 0.1% --- 0.5%
// 3 0.5% --- 1.0%
// 4 1.0% --- 2.0%
// 5 2.0% --- 4.0%
// 6 4.0% --- 8.0%
// 7 >=8.0%
// 99 not known or not detectable
if ber >= 0 && ber <= 3 {
// ber -> [0%;1%)
// Ok, can live
return nil
}
if ber >= 4 && ber <= 7 {
return fmt.Errorf("too high: %d code", ber)
}
if ber == 99 {
return fmt.Errorf("not known or not detectable")
}
return fmt.Errorf("invalid code %d", ber)
}
func getSignalQuality(port at.Port) (int, int, error) {
resp, err := port.Send("AT+CSQ")
if err != nil {
return 99, 99, err
}
if !resp.Check() || !resp.CheckFront("+CSQ: ") {
return 99, 99, fmt.Errorf("error response: %s", resp)
}
values := strings.Split(strings.ReplaceAll(strings.Split(resp.RmFront("+CSQ: ").String(), "\n")[0], "\r", ""), ",")
if len(values) != 2 {
return 99, 99, fmt.Errorf("invalid values(len): [% s]", values)
}
rssi, err := strconv.Atoi(values[0])
if err != nil {
return 99, 99, fmt.Errorf("parse rssi: %w", err)
}
ber, err := strconv.Atoi(values[1])
if err != nil {
return 99, 99, fmt.Errorf("parse ber: %w", err)
}
return rssi, ber, nil
}

35
main.go
View File

@ -3,6 +3,7 @@ package main
import ( import (
"log" "log"
"os" "os"
"time"
"gitea.unprism.ru/KRBL/sim-modem/api/modem" "gitea.unprism.ru/KRBL/sim-modem/api/modem"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/at" "gitea.unprism.ru/KRBL/sim-modem/api/modem/at"
@ -42,19 +43,8 @@ func mainE() error {
// logger.Printf("DATA: %+v\n", m.GetData()) // logger.Printf("DATA: %+v\n", m.GetData())
logger.Println("||||||||||||||||| SMS |||||||||||||||||") 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
// // }
// if ms, err := m.Sms().ReadNew(); err != nil {
// return err
// } else {
// logger.Println("NEW:", ms)
// }
Cmd := func(cmd string) { Cmd := func(cmd string) {
resp, err := m.At().Send(cmd) resp, err := m.At().SendWithTimeout(cmd, 50*time.Millisecond)
logger.Println(cmd, "===>", resp, err) logger.Println(cmd, "===>", resp, err)
} }
_ = Cmd _ = Cmd
@ -67,16 +57,27 @@ func mainE() error {
_ = buf _ = buf
// Select ME PMS // 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("SEND SMS")
// logger.Println(m.Sms().Send("+79218937173", "CGSG forever!!!")) // logger.Println(m.Sms().Send("+79218937173", "CGSG forever!!!"))
// m.At().RawSend("\r\n\x1A\r\n") // 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")
for { for {
// 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) readLen, err := m.At().SerialPort().Read(buf)
if err != nil { if err != nil {
return err return err