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
IsConnected() bool
RawSend(msg string) (string, error)
RawSend(msg string, timeout time.Duration) (string, error)
Send(cmd string) (Resp, error)
SendWithTimeout(cmd string, timeout time.Duration) (Resp, error)
io.Closer
}
@ -106,7 +107,7 @@ func (p *atPort) IsConnected() bool {
}
// 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()
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 {
return "", fmt.Errorf("serial port write: %w", err)
}
// time.Sleep(time.Millisecond)
time.Sleep(timeout)
// Read
outBuf := make([]byte, 0)
readLoop:
@ -131,13 +132,26 @@ 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
}
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 {
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/internet"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/sms"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/utils"
)
type ModemData struct {
@ -53,6 +54,7 @@ type Modem interface {
IsConnected() bool
Update() error
GetData() ModemData
CheckSignal() error
PowerOn() 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 {
m.onOffPin.PowerOn() // DEBUG do not want to wait 30 seconds
return nil
@ -276,10 +282,10 @@ func (m *modem) saveGPS(path string) error {
// Short way to send command
func (m *modem) printCmd(cmd string) {
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 {
_ = resp
m.logger.Println("CMD", cmd, ":", resp)
// m.logger.Println("CMD", cmd, "===>", resp)
}
}
@ -304,6 +310,16 @@ func (m *modem) setupPort() error {
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) {
defer func() {
if outErr != nil { // Clear port if there is error
@ -327,8 +343,9 @@ func (m *modem) checkPort(portName string) (outErr error) {
// m.restart()
// 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 {

View File

@ -5,6 +5,7 @@ import (
"io"
"log"
"strings"
"time"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/at"
)
@ -40,7 +41,7 @@ func (d *dialer) Init() error {
}
// Setup prefered message storage
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
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
}
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 {
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 (
"log"
"os"
"time"
"gitea.unprism.ru/KRBL/sim-modem/api/modem"
"gitea.unprism.ru/KRBL/sim-modem/api/modem/at"
@ -42,19 +43,8 @@ func mainE() error {
// logger.Printf("DATA: %+v\n", m.GetData())
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) {
resp, err := m.At().Send(cmd)
resp, err := m.At().SendWithTimeout(cmd, 50*time.Millisecond)
logger.Println(cmd, "===>", resp, err)
}
_ = Cmd
@ -67,16 +57,27 @@ func mainE() error {
_ = 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")
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 {
// 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