Modem Hard Reset - expose the function to users

On occasion (repeatable - if you disconnect the battery but have USB connected) the modem will stop responding to AT commands, it is therefore useless, and the entire point of being connected is compromised…

All attempts to restart the modem, and reconfigure it with Cellular.off() / Cellular.command() etc will fail, as there is no response to the AT prompt, and these functions work by relying on an AT response.

The only way to recover is to reset the entire unit which in turn issues a hardware reset to the modem.

In the file mdm_hal.cpp there is this function

void MDMParser::reset(void)
{
    MDM_INFO("[ Modem reset ]");
    unsigned delay = 100;
    if (_dev.dev == DEV_UNKNOWN || _dev.dev == DEV_SARA_R410) {
        delay = 10000; // SARA-R4: 10s
    }
    HAL_GPIO_Write(RESET_UC, 0);
    HAL_Delay_Milliseconds(delay);
    HAL_GPIO_Write(RESET_UC, 1);
}

It seems to me that this would be a useful function to make public, then issue a real modem reset when necessary.

This works a treat using Rikkas Electronsample

Fault Tolerance Code

I modified the checks it carries out to see if the AT / OK stops coming back, (and got rid of the PING as it doesn’t work)

void ConnectionCheck::loop() {
	#define MODEM_POLL_FOR_OK_MSEC 10000
	// Check cellular status - used for event logging mostly
	bool temp = Cellular.ready();
	if (temp != isCellularReady) {
		// Cellular state changed
		isCellularReady = temp;
		Log.info("cellular %s", isCellularReady ? "up" : "down");
	}



	if (millis() - listenWaitForOK >= MODEM_POLL_FOR_OK_MSEC) {
		listenWaitForOK = millis();
		if (!CheckForModemResponseOK()){
			Log.info("Modem didn't respond, rebooting modem (not rebooting processor)");
			fullModemReset();
		}
	}


	if (Cellular.listening()) {
		// Entered listening mode (blinking blue). Could be from holding down the MODE button, or
		// by repeated connection failures, see: https://github.com/spark/firmware/issues/687
		if (listeningStart == 0) {
			listeningStart = millis();
			Log.info("entered listening mode");
		}
		else {
			if (listenWaitForReboot != 0 && millis() - listeningStart >= listenWaitForReboot) {
				// Reboot
				fullModemReset();
			}
		}
	}
}


bool ConnectionCheck::CheckForModemResponseOK(){
	if (RESP_OK == Cellular.command("AT\r\n")){
		return true;
	}
	return false;
}

Then if anything goes wrong I simply wiggle the pins on the reset line of the Modem, clear the state, and reconnect.


void ConnectionCheck::fullModemReset() {

	Log.info("fullModemReset - resetting modem");

	// Reset the modem and SIM card
	// 16:MT silent reset (with detach from network and saving of NVM parameters), with reset of the SIM card
	//Cellular.command(30000, "AT+CFUN=16\r\n");
	ModemHardReset();
	
	delay(1000);

	//tell the processor to clear any state. 
	Cellular.disconnect();
	cloud_connect();


}


//firmware\hal\src\electron\modem\mdm_hal.cpp
void ConnectionCheck::ModemHardReset(){
 Log.info("[ Modem  Hard reset ]");
    const unsigned delay = 100;
    HAL_GPIO_Write(RESET_UC, 0);
    HAL_Delay_Milliseconds(delay);
    HAL_GPIO_Write(RESET_UC, 1);
}

It doesn’t quite work.

While the modem comes up and reconnects, some of the existing sockets leave artifacts.

The function below needs to be called again, but it has a flag on it to get only called on boot.

int MDMParser::socketSocket(IpProtocol ipproto, int port)

if (!checkedOnce) {
        checkedOnce = true; // prevent re-entry
        DEBUG_D("On first socketSocket use, free all open sockets\r\n");
        // Clean up any open sockets, we may have power cycled the STM32
        // while the modem remained connected.
        for (int s = 0; s < NUMSOCKETS; s++) {
            _socketCloseHandleIfOpen(s);
            // re-initialize the socket element
            _socketFree(s);
        }
    }

Let me ping someone that might be able to help, @rickkas7 or @ParticleD are you able to assist?

Sorry for resurrecting this thread, but a function to reset modem’s configuration would be great.

1 Like