This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nrf9160 modem not responding after switching to offline mode

My application uses the nrf9160 in eDRX mode. I regularly have the problem, that when switching the modem to OFFLINE mode (same for POWER-OFF mode), the modem is not responding anymore to any AT commands. I need to switch to OFFLINE mode for battery saving and for switching between Cat-M1 and Cat-NB1.

I wrote a minimalistic application for the demo board (PCA10090 0.8.5, modem Firmware 1.0.0), where I can reproduce the problem.

First the modem is configured to LTE Cat-M1 mode with an eDRX intervall of 82 seconds. Then it is set so ONLINE mode. After a connection is established or a timeout of 100 seconds expires, the modem is set to OFFLINE mode. Then this sequence is repeated.

For the application to run, the AT Command Driver and Logging with synchronous processing must be configured.

Here is the application code for the demo board:

#include <zephyr.h>
#include <stdio.h>
#include <stdlib.h>
#include <uart.h>
#include <string.h>
#include <logging/log.h>
#include <at_cmd.h>

LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG);

volatile int regStatus = 0;

static void modem_NotificationHandler(char* msg)
{
  LOG_DBG("%s", msg);
  if (memcmp(msg, "+CEREG:", strlen("+CEREG:")) == 0)
  {
    char* p = msg + strlen("+CEREG:");
    regStatus = strtol(p, NULL, 10);
  }
}

void main(void)
{
  const u32_t timeout = 100;
  bool connected;
  u32_t t = 0;

	LOG_DBG("application started");

  at_cmd_set_notification_handler(modem_NotificationHandler);
  at_cmd_write("AT+CEREG=3", NULL, 0, NULL);

  while (1)
  {
    regStatus = 0;
    LOG_DBG("configuring modem");
    at_cmd_write("AT%XSYSTEMMODE=1,0,0,0", NULL, 0, NULL); // LTE Cat-M1
    at_cmd_write("AT+CEDRXS=2,4,\"0101\"", NULL, 0, NULL); // 81.92 seconds
    LOG_DBG("modem configured");
    at_cmd_write("AT+CFUN=1", NULL, 0, NULL);
    LOG_DBG("connecting . . .");
    t = 0;
    connected = false;
    while (!connected && t++ < timeout)
    {
      k_sleep(1000);
      connected = regStatus == 1 || regStatus == 5;
    }
    if (connected)
    {
      LOG_DBG("connected");
      k_sleep(10000);
    }
    else
    {
      LOG_DBG("connection timed out");
    }
    LOG_DBG("setting modem to OFFLINE");
    at_cmd_write("AT+CFUN=4", NULL, 0, NULL);
    LOG_DBG("modem set to OFFLINE");
  }
}

After the second connection cycle, when setting the modem to OFFLINE mode, the modem is not responding anymore.

Here is the output:

***** Booting Zephyr OS build v1.14.99-ncs3-snapshot2-1276-g4493a423a645 *****
[00:00:00.365,661] <dbg> main.main: application started
[00:00:00.371,734] <dbg> main.main: configuring modem
[00:00:00.379,455] <dbg> main.main: modem configured
[00:00:00.415,435] <dbg> main.main: connecting . . .
[00:00:30.800,292] <dbg> main.modem_NotificationHandler: +CEREG: 2,"0328","010D2B08",7,0,0

[00:01:05.904,235] <dbg> main.modem_NotificationHandler: +CEREG: 5,"0328","010D2B08",7

[00:01:05.912,994] <dbg> main.modem_NotificationHandler: +CEDRXP: 4,"0101","0101","0000"

[00:01:06.426,910] <dbg> main.main: connected
[00:01:16.431,854] <dbg> main.main: setting modem to OFFLINE
[00:01:16.592,407] <dbg> main.modem_NotificationHandler: +CEREG: 0,"0328","010D2B08",7,0,0

[00:01:18.002,746] <dbg> main.main: modem set to OFFLINE
[00:01:18.008,575] <dbg> main.main: configuring modem
[00:01:18.022,521] <dbg> main.main: modem configured
[00:01:18.064,727] <dbg> main.main: connecting . . .
[00:01:19.749,694] <dbg> main.modem_NotificationHandler: +CEREG: 2,"0328","01158B05",7,0,0

[00:02:58.079,345] <dbg> main.main: connection timed out
[00:02:58.085,144] <dbg> main.main: setting modem to OFFLINE

Any suggestions?

  • Can you please flash this to your Development Kit witht the nRF Programmer application in the nRF Connect app, just want to check if this just a code issue or something related to the specific at commands you are sending.

    This is a basic application I made a long time ago when I was new to socket programming that simply configures the modem for NB-IoT and repeats the process every 5 seconds. Tested this on my DK there and it still works. You won't get any CEREG notifications as it's not configured to do that but you should get the modem firing out AT commands happily.

    The code is based off the source code for the at_client application. Do remove the numbers at the start of the file name, it's randomly added by the DevZone when I upload these hex files Sweat smile

    5025.merged.hex

  • I'm afraid I cannot blindly install software from a source that is not validated - I would violate our company policy ;-)

    But I will be happy to try it if you could send the source code, so I can check it out and compile it myself!

  • That's fair enough.

    main.c:

    /*
     * Copyright (c) 2018 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
     */
    
    #include <zephyr.h>
    #include <stdio.h>
    #include <uart.h>
    #include <string.h>
    #include <bsd.h>
    #include <net/socket.h>
    
    #define AT_XSYSTEMMODE_GPS 			"AT\%XSYSTEMMODE=0,0,1,0"
    #define AT_MAGPIO_GPS      			"AT\%XMAGPIO=1,0,0,1,1,1574,1577"
    #define AT_CFUN_ON        			"AT+CFUN=1"
    #define AT_XSYSTEMMODE_LTE			"AT\%XSYSTEMMODE=0,1,0,0"
    #define AT_CFUN_OFF							"AT+CFUN=4"
    #define AT_MAGPIO_CLEAR					"AT\%XMAGPIO"
    #define AT_CEREG_LVL1						"AT+CEREG=1"
    #define AT_CEREG_CHECK					"AT+CEREG?"
    
    static const char			at_commands_LTE[][31]  = { AT_CFUN_OFF, AT_XSYSTEMMODE_LTE, AT_MAGPIO_CLEAR, AT_CFUN_ON };
    
    #if defined(CONFIG_BSD_LIBRARY)
    
    /**@brief Recoverable BSD library error. */
    void bsd_recoverable_error_handler(uint32_t err)
    {
    	printk("bsdlib recoverable error: %lu\n", err);
    }
    
    /**@brief Irrecoverable BSD library error. */
    void bsd_irrecoverable_error_handler(uint32_t err)
    {
    	printk("bsdlib irrecoverable error: %lu\n", err);
    
    	__ASSERT_NO_MSG(false);
    }
    
    #endif /* defined(CONFIG_BSD_LIBRARY) */
    
    static int send_at_command(int pSelector)
    {
    	int  at_sock;
    	int  bytes_sent;
    	int  bytes_received;
    	char buf[20];
      char at_command[4][31];
    
    	switch (pSelector)
    	{
    		case 0:
    			memcpy(at_command, at_commands_LTE, sizeof(at_commands_LTE));
    			break;
    		default:
    			printk("Error setting AT commands\n");
    			break;
    	}
    	printk("Checking the network\n");
    	at_sock = socket(AF_LTE, 0, NPROTO_AT);
    
    	if (at_sock < 0) {
    		printk("Socket failed to open\n");
    		return -1;
    	}
    	printk("Socket ID: %d\n", at_sock);
    
    	for (int i = 0; i < ARRAY_SIZE(at_command); i++)
    	{
    		printk("Sending AT command: %s\n", at_command[i]);
    		bytes_sent = send(at_sock, at_command[i],
    				  strlen(at_command[i]), 0);
    
    		if (bytes_sent < 0) {
    			close(at_sock);
    			return -1;
    		}
    
    		do {
    			bytes_received = recv(at_sock, buf, 50, 0);
    		} while (bytes_received == 0);
    		printk("Modem response: %s\n",buf);
    		printk("Bytes received: %d\n",bytes_received);
    		switch (bytes_received)
    		{
    			case 5:
    				if (memcmp(buf, "OK", 2) != 0)
    				{
    					printk("Error with Modem Bytes received\n");
    					close(at_sock);
    					return -1;
    				}
    				break;
    			default:
    				printk("Invalid case for AT Check\n");
    		}
    	}
    	close(at_sock);
    	return 0;
    }
    
    void main(void)
    {
    	printk("Application started\n");
    	while(1)
    	{
    		printk("Testing Modem\n");
    		send_at_command(0);
    		printk("Waiting 5 seconds\n");
    		k_sleep(K_MSEC(5000));
    	}
    }
    

    prj.conf:

    # Use the development test RNG (not for production)
    CONFIG_TEST_RANDOM_GENERATOR=y
    
    # Networking, enable networking APIs
    CONFIG_NETWORKING=y
    CONFIG_NET_SOCKETS_OFFLOAD=y
    CONFIG_NET_SOCKETS=y
    
    # Allow Socket APIs to use POSIX names like socket(), send(), etc
    # Careful with close(), close() only works on sockets when enabled
    CONFIG_NET_SOCKETS_POSIX_NAMES=y
    
    # BSD library
    CONFIG_BSD_LIBRARY=y
    
    # Main thread, reuse init stack
    CONFIG_MAIN_THREAD_PRIORITY=7
    CONFIG_MAIN_STACK_SIZE=4096
    
    # Available memory for k_malloc
    CONFIG_HEAP_MEM_POOL_SIZE=1024
    
    # Enable stdout for printfs
    CONFIG_STDOUT_CONSOLE=y
    
    # Logging
    CONFIG_LOG=y
    CONFIG_LOG_DEFAULT_LEVEL=4
    
    # Build with newlib c library
    CONFIG_NEWLIB_LIBC=y
    CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y
    
    # Enable non-secure firmware as Normal mode
    CONFIG_TRUSTED_EXECUTION_NONSECURE=y
    

    CMakeLists.txt:

    #
    # Copyright (c) 2018 Nordic Semiconductor
    #
    # SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
    #
    
    cmake_minimum_required(VERSION 3.8.2)
    
    set(BOARD nrf9160_pca10090ns)
    
    include(../../../cmake/boilerplate.cmake NO_POLICY_SCOPE)
    include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
    project(Socket)
    
    target_sources(app PRIVATE src/main.c)
    zephyr_include_directories(src)
    

  • Thank you for your sample. It seems to work as expected. But I don't think there's a problem with the sockets, but with the specific sequence of commands and the state the modem is in at that instant. The problem occurs when the modem is in eDRX mode, has no active connection (network status == 2) and is then set to OFFLINE or POWER_OFF.

    No issue when not in eDRX, as in your example.

    BTW, I see the same behavior with the AT_HOST sample, as I posted above.

  • Have you considered only using eDRX when your device is going to be idle for a reasonable period and disabling eDRX when activily using the modem?

Related