While developing my project, I need to receive UDP packets with the NRF9151.
My configuration is as follows:
- 1nce SIM
- VPN between my UDP service and the 1nce network (to eliminate NAT issues)
- Roaming connection in Italy with Vodafone
Starting from the udp/sample example that cyclically sends UDP packets, I also added the reception part. I immediately noticed that the packet was received by the device only if sent within about 5 seconds. The 5-second period coincides with the time between send and "RCC Idle."
I further tested by eliminating transmission on the device and focusing on reception.
From the tests I performed, it appears that the same code receives packets regularly if the NRF9151 is configured in LTEM mode.
By modifying the firmware to operate in NBIOT mode, all packets are lost.
In reality, even in NBIOT, for each packet sent, the modem switches from the RCC Idle state to the RCC Connect state and vice versa, but the socket does not receive any data.
This is my main.c
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/net/socket.h>
#include <modem/lte_lc.h>
#include <modem/nrf_modem_lib.h>
#define UDP_IP_HEADER_SIZE 28
static int client_fd;
static struct sockaddr_storage host_addr;
static struct k_work_delayable socket_transmission_work;
static int data_upload_iterations = CONFIG_UDP_DATA_UPLOAD_ITERATIONS;
static uint8_t recv_buf[CONFIG_UDP_DATA_UPLOAD_SIZE_BYTES];
struct sockaddr_in local_addr = {
.sin_family = AF_INET, /**< AF_INET */
.sin_port = htons(5683), /**< Port number */
.sin_addr.s_addr = INADDR_ANY, /**< IPv4 address */
};
K_SEM_DEFINE(lte_connected_sem, 0, 1);
K_SEM_DEFINE(modem_shutdown_sem, 0, 1);
static void socket_transmission_work_fn(struct k_work *work)
{
int err;
char buffer[CONFIG_UDP_DATA_UPLOAD_SIZE_BYTES] = {"Maurizio\0"};
printk("Transmitting UDP/IP payload of %d bytes to the ",
CONFIG_UDP_DATA_UPLOAD_SIZE_BYTES + UDP_IP_HEADER_SIZE);
printk("IP address %s, port number %d\n",
CONFIG_UDP_SERVER_ADDRESS_STATIC,
CONFIG_UDP_SERVER_PORT);
#if defined(CONFIG_UDP_RAI_LAST)
/* Let the modem know that this is the last packet for now and we do not
* wait for a response.
*/
int rai = RAI_LAST;
err = setsockopt(client_fd, SOL_SOCKET, SO_RAI, &rai, sizeof(rai));
if (err) {
printk("Failed to set socket option, error: %d\n", errno);
}
#endif
#if defined(CONFIG_UDP_RAI_ONGOING)
/* Let the modem know that we expect to keep the network up longer.
*/
int rai = RAI_ONGOING;
err = setsockopt(client_fd, SOL_SOCKET, SO_RAI, &rai, sizeof(rai));
if (err) {
printk("Failed to set socket option, error: %d\n", errno);
}
#endif
//err = send(client_fd, buffer, sizeof(buffer), 0);
err = sendto(client_fd, buffer, sizeof(buffer), 0, (struct sockaddr *)&host_addr, sizeof(host_addr));
if (err < 0) {
printk("Failed to transmit UDP packet, error: %d\n", errno);
}
#if defined(CONFIG_UDP_RAI_NO_DATA)
/* Let the modem know that there will be no upcoming data transmission anymore.
*/
int rai = RAI_NO_DATA;
err = setsockopt(client_fd, SOL_SOCKET, SO_RAI, &rai, sizeof(rai));
if (err) {
printk("Failed to set socket option, error: %d\n", errno);
}
#endif
/* Transmit a limited number of times and then shutdown. */
if (data_upload_iterations > 0) {
data_upload_iterations--;
} else if (data_upload_iterations == 0) {
k_sem_give(&modem_shutdown_sem);
/* No need to schedule work if we're shutting down. */
return;
}
/* Schedule work if we're either transmitting indefinitely or
* there are more iterations left.
*/
k_work_schedule(&socket_transmission_work,
K_SECONDS(CONFIG_UDP_DATA_UPLOAD_FREQUENCY_SECONDS));
}
static void work_init(void)
{
k_work_init_delayable(&socket_transmission_work, socket_transmission_work_fn);
}
static void lte_handler(const struct lte_lc_evt *const evt)
{
switch (evt->type) {
case LTE_LC_EVT_NW_REG_STATUS:
if ((evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_HOME) &&
(evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_ROAMING)) {
break;
}
printk("Network registration status: %s\n",
evt->nw_reg_status == LTE_LC_NW_REG_REGISTERED_HOME ?
"Connected - home" : "Connected - roaming");
k_sem_give(<e_connected_sem);
break;
case LTE_LC_EVT_PSM_UPDATE:
printk("PSM parameter update: TAU: %d s, Active time: %d s\n",
evt->psm_cfg.tau, evt->psm_cfg.active_time);
break;
case LTE_LC_EVT_EDRX_UPDATE:
printk("eDRX parameter update: eDRX: %.2f s, PTW: %.2f s\n",
(double)evt->edrx_cfg.edrx, (double)evt->edrx_cfg.ptw);
break;
case LTE_LC_EVT_RRC_UPDATE:
printk("RRC mode: %s\n",
evt->rrc_mode == LTE_LC_RRC_MODE_CONNECTED ? "Connected" : "Idle\n");
break;
case LTE_LC_EVT_CELL_UPDATE:
printk("LTE cell changed: Cell ID: %d, Tracking area: %d\n",
evt->cell.id, evt->cell.tac);
break;
case LTE_LC_EVT_RAI_UPDATE:
/* RAI notification is supported by modem firmware releases >= 2.0.2 */
printk("RAI configuration update: "
"Cell ID: %d, MCC: %d, MNC: %d, AS-RAI: %d, CP-RAI: %d\n",
evt->rai_cfg.cell_id,
evt->rai_cfg.mcc,
evt->rai_cfg.mnc,
evt->rai_cfg.as_rai,
evt->rai_cfg.cp_rai);
break;
default:
break;
}
}
static int socket_connect(void)
{
int err;
struct sockaddr_in *server4 = ((struct sockaddr_in *)&host_addr);
server4->sin_family = AF_INET;
server4->sin_port = htons(CONFIG_UDP_SERVER_PORT);
inet_pton(AF_INET, CONFIG_UDP_SERVER_ADDRESS_STATIC, &server4->sin_addr);
client_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (client_fd < 0) {
printk("Failed to create UDP socket, error: %d\n", errno);
err = -errno;
return err;
}
err = bind(client_fd, (struct sockaddr *)&local_addr,
sizeof(local_addr));
if (err < 0) {
printk("Failed to bind socket, error: %d\n", err);
close(client_fd);
return err;
}
/* err = connect(client_fd, (struct sockaddr *)&host_addr, sizeof(struct sockaddr_in));
if (err < 0) {
printk("Failed to connect socket, error: %d\n", errno);
close(client_fd);
return err;
} */
return 0;
}
int main(void)
{
int err;
int received;
printk("UDP sample has started\n");
work_init();
err = nrf_modem_lib_init();
if (err) {
printk("Failed to initialize modem library, error: %d\n", err);
return -1;
}
#if defined(CONFIG_UDP_RAI_ENABLE) && defined(CONFIG_SOC_NRF9160)
/* Enable Access Stratum RAI support for nRF9160.
* Note: The 1.3.x modem firmware release is certified to be compliant with 3GPP Release 13.
* %REL14FEAT enables selected optional features from 3GPP Release 14. The 3GPP Release 14
* features are not GCF or PTCRB conformance certified by Nordic and must be certified
* by MNO before being used in commercial products.
* nRF9161 is certified to be compliant with 3GPP Release 14.
*/
err = nrf_modem_at_printf("AT%%REL14FEAT=0,1,0,0,0");
if (err) {
printk("Failed to enable Access Stratum RAI support, error: %d\n", err);
return -1;
}
#endif
err = lte_lc_connect_async(lte_handler);
if (err) {
printk("Failed to connect to LTE network, error: %d\n", err);
return -1;
}
k_sem_take(<e_connected_sem, K_FOREVER);
err = socket_connect();
if (err) {
return -1;
}
// Disable work scheduling for now, as we want to test the reception of UDP packets from the server first.
//k_work_schedule(&socket_transmission_work, K_NO_WAIT);
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
while (1) {
printk("Waiting received data\n");
//received = recv(client_fd, recv_buf, sizeof(recv_buf), 0);
received = recvfrom(client_fd, recv_buf, sizeof(recv_buf), 0,(struct sockaddr *)&client_addr, &client_addr_len);
//received = recv(client_fd, recv_buf, 8, 0);
if (received < 0) {
printk("Socket error: %d, exit\n", errno);
break;
} if (received == 0) {
printk("Empty datagram\n");
continue;
}
recv_buf[received] = '\0';
printk("Received %s\n", recv_buf);
}
k_sem_take(&modem_shutdown_sem, K_FOREVER);
err = nrf_modem_lib_shutdown();
if (err) {
return -1;
}
return 0;
}
The prj.conf derive from usp/sample
# # Copyright (c) 2020 Nordic Semiconductor ASA # # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause # # General config CONFIG_PICOLIBC_IO_FLOAT=y CONFIG_NCS_SAMPLES_DEFAULTS=y CONFIG_SERIAL=y # Network CONFIG_NETWORKING=y CONFIG_NET_NATIVE=n CONFIG_NET_SOCKETS=y CONFIG_NET_SOCKETS_OFFLOAD=y CONFIG_POSIX_API=y # LTE link control CONFIG_LTE_LINK_CONTROL=y # Modem library CONFIG_NRF_MODEM_LIB=y # Heap and stacks CONFIG_HEAP_MEM_POOL_SIZE=1024 CONFIG_MAIN_STACK_SIZE=4096 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 # LTE parameters ## PSM CONFIG_UDP_PSM_ENABLE=n CONFIG_LTE_PSM_REQ_RPTAU="00100001" CONFIG_LTE_PSM_REQ_RAT="00000000" ## eDRX CONFIG_UDP_EDRX_ENABLE=n ## RAI CONFIG_UDP_RAI_ENABLE=n ## Enable required LTE link control modules CONFIG_LTE_LC_EDRX_MODULE=y CONFIG_LTE_LC_PSM_MODULE=y CONFIG_LTE_LC_RAI_MODULE=y ## Maurizio CONFIG_UDP_DATA_UPLOAD_FREQUENCY_SECONDS=90 CONFIG_LTE_NETWORK_MODE_NBIOT=y #CONFIG_LTE_NETWORK_MODE_LTE_M=y CONFIG_UDP_SERVER_ADDRESS_STATIC="10.64.193.81" CONFIG_UDP_SERVER_PORT=5683 #CONFIG_UDP_SERVER_PORT=10000 CONFIG_UDP_DATA_UPLOAD_SIZE_BYTES=30 # Enable Packet Data Network (PDN) library CONFIG_PDN=y CONFIG_PDN_DEFAULTS_OVERRIDE=y # Set your custom APN CONFIG_PDN_DEFAULT_APN="iot.1nce.net" # Opzionale: imposta la famiglia IP (IPv4, IPv6 o IPv4V6) CONFIG_PDN_DEFAULT_FAM_IPV4=y # Abilita il blocco su un PLMN specifico CONFIG_LTE_LOCK_PLMN=y # Inserisci il codice MCCMNC dell'operatore (es. 22210 per VODAFONE IT) CONFIG_LTE_LOCK_PLMN_STRING="22210" #CONFIG_NRF_MODEM_LIB_TRACE=y
The serial output for NBIOT is:
LTE cell changed: Cell ID: 7593841, Tracking area: 17095 RRC mode: Connected Network registration status: Connected - roaming Waiting received data PSM parameter update: TAU: 7200 s, Active time: -1 s RRC mode: Idle RRC mode: Connected RRC mode: Idle RRC mode: Connected RRC mode: Idle
The same log with LTEM (whree the data are reeceived) is:
*** Booting nRF Connect SDK v3.2.4-4c3fc0d44534 *** *** Using Zephyr OS v4.2.99-9673eec75908 *** UDP sample has started I: Trace thread ready I: Trace level override: 2 LTE cell changed: Cell ID: 7593761, Tracking area: 13007 RRC mode: Connected Network registration status: Connected - roaming Waiting received data PSM parameter update: TAU: 3600 s, Active time: -1 s RRC mode: Idle RRC mode: Connected Received 12:19:53 Waiting received data RRC mode: Idle RRC mode: Connected Received 12:20:14 Waiting received data RRC mode: Idle
Using Cellular Monitor, I dumped modem activity in both the NB IoT and LTE cases:
Cellular-Monitor-NBIOT-device.pcapng
Cellular-Monitor-LTEM-device.pcapng
Please help me to solve the problem.