Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve flow control for reading sim card status #31

Merged
merged 2 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 29 additions & 23 deletions cmd/modemd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,15 @@ func runMain() error {
mc := ModemController{
StartTime: time.Now(),
//ModemsConfig: conf.ModemsConfig,
ModemsConfig: m,
TestHosts: conf.TestHosts,
TestInterval: conf.TestInterval,
PowerPin: conf.PowerPin,
InitialOnDuration: conf.InitialOnDuration,
FindModemDuration: conf.FindModemDuration,
ConnectionTimeout: conf.ConnectionTimeout,
PingWaitTime: conf.PingWaitTime,
PingRetries: conf.PingRetries,
ModemsConfig: m,
TestHosts: conf.TestHosts,
TestInterval: conf.TestInterval,
PowerPin: conf.PowerPin,
InitialOnDuration: conf.InitialOnDuration,
FindModemDuration: conf.FindModemDuration,
ConnectionTimeout: conf.ConnectionTimeout,
PingWaitTime: conf.PingWaitTime,
//PingRetries: conf.PingRetries,
RequestOnDuration: conf.RequestOnDuration,
RetryInterval: conf.RetryInterval,
RetryFindModemInterval: conf.RetryFindModemInterval,
Expand All @@ -112,13 +112,19 @@ func runMain() error {
}

for {
// =========== Wait until modem should be on ===========
// =========== Power off modem if it shouldn't be on then wait until it should be on ===========
if !mc.ShouldBeOn() {
log.Println("Waiting until modem should be powered on.")
log.Println("Powering off USB modem.")
if err := mc.SetModemPower(false); err != nil {
return err
}
mc.Modem = nil
for !mc.ShouldBeOn() {
time.Sleep(5 * time.Second)
}
}

// =========== Power on modem ===========
if err := mc.SetModemPower(true); err != nil {
return err
}
Expand Down Expand Up @@ -183,17 +189,20 @@ func runMain() error {
for retries := 5; retries > 0; retries-- {
simStatus, err := mc.CheckSimCard()
if err == nil && simStatus == "READY" {
mc.Modem.SimReady = true
mc.Modem.SimCardStatus = SimCardReady
break
}
log.Printf("SIM card not ready. Will cycle power %d more time(s) to find SIM card", retries)
log.Printf("SIM card not ready. Will try %d more time(s) to find SIM card", retries)
time.Sleep(5 * time.Second)
}
if !mc.Modem.SimReady {
mc.failedToFindSimCard = true
if mc.Modem.SimCardStatus != SimCardReady {
mc.Modem.SimCardStatus = SimCardFailed
makeModemEvent("noModemSimCard", &mc)
mc.failedToFindSimCard = true
continue
}
mc.failedToFindSimCard = false
log.Info("SIM card ready.")

// ========== Checking signal strength. =============
log.Println("Checking signal strength.")
Expand Down Expand Up @@ -222,8 +231,11 @@ func runMain() error {
return err
}
if !connected {
mc.lastFailedConnection = time.Now()
makeModemEvent("modemPingFail", &mc)
// If the modem should be on but failed to connect, then make an event
if mc.ShouldBeOn() {
mc.lastFailedConnection = time.Now()
makeModemEvent("modemPingFail", &mc)
}
continue
}

Expand All @@ -248,12 +260,6 @@ func runMain() error {
break
}
}

log.Println("Powering off USB modem.")
if err := mc.SetModemPower(false); err != nil {
return err
}
mc.Modem = nil
}
}

Expand Down
44 changes: 23 additions & 21 deletions cmd/modemd/modem.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"fmt"
"os/exec"
"strings"
"time"

goconfig "github.com/TheCacophonyProject/go-config"
)
Expand All @@ -14,40 +13,43 @@ type Modem struct {
Netdev string
VendorProduct string
ATReady bool
SimReady bool
SimCardStatus SimCardStatus
}

type SimCardStatus string

const (
SimCardFinding SimCardStatus = "finding"
SimCardReady SimCardStatus = "ready"
SimCardFailed SimCardStatus = "failed"
)

// NewModem return a new modem from the config
func NewModem(config goconfig.Modem) *Modem {
m := &Modem{
Name: config.Name,
Netdev: config.NetDev,
VendorProduct: config.VendorProductID,
SimCardStatus: SimCardFinding,
}
return m
}

// PingTest will try connecting to one of the provides hosts
func (m *Modem) PingTest(timeoutSec int, retries int, hosts []string) bool {
for i := retries; i > 0; i-- {
for _, host := range hosts {
cmd := exec.Command(
"ping",
"-I",
m.Netdev,
"-n",
"-q",
"-c1",
fmt.Sprintf("-w%d", timeoutSec),
host)
if err := cmd.Run(); err == nil {
return true
}
}
if i > 1 {
log.Printf("ping test failed. %d more retries\n", i-1)
func (m *Modem) PingTest(timeoutSec int, hosts []string) bool {
for _, host := range hosts {
cmd := exec.Command(
"ping",
"-I",
m.Netdev,
"-n",
"-q",
"-c1",
fmt.Sprintf("-w%d", timeoutSec),
host)
if err := cmd.Run(); err == nil {
return true
}
time.Sleep(2 * time.Second)
}
return false
}
Expand Down
59 changes: 34 additions & 25 deletions cmd/modemd/modemController.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,17 @@ import (
)

type ModemController struct {
StartTime time.Time
Modem *Modem
ModemsConfig []goconfig.Modem
TestHosts []string
TestInterval time.Duration
PowerPin string
InitialOnDuration time.Duration
FindModemDuration time.Duration // Time in seconds after USB powered on for the modem to be found
ConnectionTimeout time.Duration // Time in seconds for modem to make a connection to the network
PingWaitTime time.Duration
PingRetries int
StartTime time.Time
Modem *Modem
ModemsConfig []goconfig.Modem
TestHosts []string
TestInterval time.Duration
PowerPin string
InitialOnDuration time.Duration
FindModemDuration time.Duration // Time in seconds after USB powered on for the modem to be found
ConnectionTimeout time.Duration // Time in seconds for modem to make a connection to the network
PingWaitTime time.Duration
//PingRetries int
RequestOnDuration time.Duration // Time the modem will stay on in seconds after a request was made
RetryInterval time.Duration
RetryFindModemInterval time.Duration
Expand Down Expand Up @@ -257,6 +257,8 @@ func (mc *ModemController) GetStatus() (map[string]interface{}, error) {
status["timestamp"] = time.Now().Format(time.RFC1123Z)
status["powered"] = mc.IsPowered
status["onOffReason"] = mc.onOffReason
status["failedToFindModem"] = mc.failedToFindModem
status["failedToFindSimCard"] = mc.failedToFindSimCard

if mc.Modem != nil {
// Set details for modem
Expand All @@ -265,7 +267,6 @@ func (mc *ModemController) GetStatus() (map[string]interface{}, error) {
modem["netdev"] = mc.Modem.Netdev
modem["vendor"] = mc.Modem.VendorProduct
modem["atReady"] = mc.Modem.ATReady
modem["simReady"] = mc.Modem.SimReady
modem["connectedTime"] = mc.connectedTime.Format(time.RFC1123Z)
if mc.Modem.ATReady {
modem["voltage"] = valueOrErrorStr(mc.readVoltage())
Expand Down Expand Up @@ -300,13 +301,13 @@ func (mc *ModemController) GetStatus() (map[string]interface{}, error) {
}

// Set details for SIM card
if mc.Modem.SimReady {
simCard := make(map[string]interface{})
simCard["simCardStatus"] = valueOrErrorStr(mc.CheckSimCard())
simCard := make(map[string]interface{})
simCard["simCardStatus"] = mc.Modem.SimCardStatus
if mc.Modem.SimCardStatus == SimCardReady {
simCard["ICCID"] = valueOrErrorStr(mc.readSimICCID())
simCard["provider"] = valueOrErrorStr(mc.readSimProvider())
status["simCard"] = simCard
}
status["simCard"] = simCard

/*
if gpsEnabled, err := mc.gpsEnabled(); err != nil {
Expand Down Expand Up @@ -821,6 +822,10 @@ func (mc *ModemController) WaitForConnection() (bool, error) {
log.Printf("Waiting %s for modem to connect", mc.ConnectionTimeout)
timeout := time.After(mc.ConnectionTimeout)
for {
if !mc.ShouldBeOn() {
log.Info("Canceling ping test as modem should be off.")
return false, nil
}
select {
case <-timeout:
mc.lastFailedConnection = time.Now()
Expand All @@ -837,7 +842,7 @@ func (mc *ModemController) WaitForConnection() (bool, error) {
if mc.PingTest() {
return true, nil
} else {
log.Println("Ping test failed.")
log.Infof("Ping test failed. Trying again until the %s timeout.", mc.ConnectionTimeout)
}
}
}
Expand All @@ -848,20 +853,24 @@ func (mc *ModemController) WaitForConnection() (bool, error) {
// - LastOnRequest: Check if the last "StayOn" request was less than 'RequestOnTime' ago.
// - OnWindow: //TODO
func (mc *ModemController) shouldBeOnWithReason() (bool, string) {
if time.Now().Before(mc.stayOffUntil) {
return false, fmt.Sprintf("Modem should be off because it was requested to stay off until %s.", mc.stayOffUntil.Format("2006-01-02 15:04:05"))
}

if time.Now().Before(mc.stayOnUntil) {
return true, fmt.Sprintf("Modem should be on because it was requested to stay on until %s.", mc.stayOnUntil.Format("2006-01-02 15:04:05"))
}

if mc.failedToFindModem {
return false, "Modem should be off because it could not be found on boot."
}

if mc.failedToFindSimCard {
return false, "Modem should be off because it failed to find a SIM card."
return false, "Modem should be off because it could not find a SIM card."
}

if time.Now().Before(mc.stayOffUntil) {
return false, fmt.Sprintf("Modem should be off because it was requested to stay off until %s.", mc.stayOffUntil.Format("2006-01-02 15:04:05"))
}

if time.Now().Before(mc.stayOnUntil) {
return true, fmt.Sprintf("Modem should be on because it was requested to stay on until %s.", mc.stayOnUntil.Format("2006-01-02 15:04:05"))
if mc.Modem != nil && mc.Modem.SimCardStatus == SimCardFailed {
return false, "Modem should be off because it failed to find a SIM card."
}

if time.Since(mc.lastFailedConnection) < mc.RetryInterval {
Expand Down Expand Up @@ -941,5 +950,5 @@ func (mc *ModemController) WaitForNextPingTest() bool {

func (mc *ModemController) PingTest() bool {
seconds := int(mc.PingWaitTime / time.Second)
return mc.Modem.PingTest(seconds, mc.PingRetries, mc.TestHosts)
return mc.Modem.PingTest(seconds, mc.TestHosts)
}