Cat-M1 + UDP
Test Simple UDP send/recv using LTE Cat-M.1
Let's send and recv UDP packet to soonisys's echo server.
We provide two free UDP test servers. "please don't attack our free servers...T.T"
Normal UDP echo server
The server simply sends back the received packet.
IPv4 - Address: 3.37.91.140 Port: 39633
Increase first byte UDP server
The server increase(+1) the first byte of the packet and sends it back.
IPv4 - Address: 3.37.91.140 Port: 39634
ex> device send:A1 B3 12 03 -> server send back:A2 B3 12 03
We will use 'Increase first byte' server to test UDP.
The echo server service is closed.
1. Preparations
nRF9160 M.2 Development Kit
LTE-M Nano-Simcard(We use 'things mobile' sim card)
2. Create Project
See Create Project.
Create project named 'mySooniUDP'. (You can choose any name)
3. Source Codes
3.1 src/main.c
#include <zephyr.h>
#include <zephyr/types.h>
#include <sys/printk.h>
#include <device.h>
#include <devicetree.h>
#include <drivers/gpio.h>
#include <modem/lte_lc.h>
#include <net/socket.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#define SERVER_ADDR "52.78.123.53"
#define SERVER_PORT 39634 // server increase first byte
static int sock;
static struct pollfd fds;
static struct sockaddr_storage server_addr;
static uint8_t tx_buf[512]; // we have a lot of ram space!!!!
static uint8_t rx_buf[512]; // me too
// return 0: we got the packet
// return -EAGAIN : no packet
static int wait(int timeout)
{
int ret = poll(&fds, 1, timeout);
if (ret == 0) return -EAGAIN; // no packet
if (ret < 0)
{
printk("@modem.wait:poll err=%d\n", errno);
return -errno;
}
if ((fds.revents & POLLERR) == POLLERR) {
printk("@modem.wait:POLLERR\n");
return -EIO;
}
if ((fds.revents & POLLNVAL) == POLLNVAL) {
printk("@modem.wait:POLLNVAL\n");
return -EBADF;
}
if ((fds.revents & POLLIN) != POLLIN) return -EAGAIN;
return 0; // packet exsist
}
// return -1 : error
// return 0 :no packet
// return >0 :recv packet size
int udp_recv(uint8_t *buf, int maxlen, int timeout_ms)
{
int ret;
if(maxlen <= 0) return -1; // parameter error:maxlen must be larger then 0
if(timeout_ms <= 0) return -1; // parameter error:timeout_ms must be larger then 0
ret = wait(timeout_ms);
if (ret < 0)
{
if (ret == -EAGAIN) return 0; // no packet
printk("@modem.recv:wait err=%d\n", ret);
return ret; // error on 'wait'
}
ret = recv(sock, buf, maxlen, MSG_DONTWAIT);
if (ret < 0)
{
if (errno == EAGAIN || errno == EWOULDBLOCK) return 0;
else
{
printk("@modem.recv:recv err=%d\n", ret);
return ret;
}
}
if (ret == 0) return 0; // no packet
return ret; // recv length
}
// return:sent bytes
int udp_send(uint8_t *buf, int len)
{
int ret;
ret = send(sock, buf, len, 0);
if (ret < 0)
{
printk("@modem.send:err.%d\n", errno);
}
return ret;
}
void main()
{
int err, firstByte;
int tx_ret, rx_ret;
struct sockaddr_in *server4 = ((struct sockaddr_in *)&server_addr);
printk("\n****** Hello. GettingStarted - mySooniUDP ******\n");
// #1. LTE link
printk("lte:init and connect...\n"); // takes about 10~30seconds
err = lte_lc_init_and_connect();
if (err)
{
printk("@lte:error=%d\n", err);
return;
}
printk("lte:connected.\n");
// #2. UDP Socket
// address parse
server4->sin_family = AF_INET;
server4->sin_port = htons((uint16_t)SERVER_PORT);
inet_pton(AF_INET, SERVER_ADDR, &server4->sin_addr);
// socket create
printk("socket:create...\n");
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0)
{
printk("@socket:create err=%d\n", errno);
(void)close(sock);
return;
}
printk("socket:create ok.\n");
// socket connect
printk("socket:connect...\n");
err = connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in));
if(err != 0)
{
printk("@socket:connect err=%d\n", errno);
(void)close(sock);
return;
}
printk("socket:connect ok.\n");
/* Initialize FDS, for poll. */
fds.fd = sock;
fds.events = POLLIN;
printk("let's send/recv packet\n");
// #3. while
firstByte = 0;
while(true)
{
tx_buf[0] = (uint8_t)firstByte;
rx_buf[0] = 0;
printk("packet-%d:send at %u\n", firstByte, k_uptime_get_32());
tx_ret = udp_send(tx_buf, 4);
rx_ret = udp_recv(rx_buf, 512, 5000);
if((tx_ret > 0) && (rx_ret > 0))
{
tx_buf[0]++;
if(tx_buf[0] == rx_buf[0]) printk("packet-%d:recv at %u, okay\n", firstByte, k_uptime_get_32());
else printk("packet-%d:recv at %u, wrong\n", firstByte, k_uptime_get_32());
}
else
{
printk("@packet-%d:error\n", firstByte);
// do something for exception.
}
firstByte++;
printk("sleep:8000ms...\n");
k_msleep(8000);
}
}
3.2 CMakeLists.txt
#
# Copyright (c) 2020 Nordic Semiconductor
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#
cmake_minimum_required(VERSION 3.13.1)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(mySooniUDP)
# SOURCE FILES
target_sources(app PRIVATE src/main.c)
3.3 prj.conf
#
# Copyright (c) 2020 Nordic Semiconductor ASA
#
# SPDX-License-Identiier: LicenseRef-Nordic-5-Clause
#
# General config
CONFIG_NEWLIB_LIBC=y
CONFIG_HW_STACK_PROTECTION=y
CONFIG_SERIAL=y
# GPIO
CONFIG_GPIO=y
# LTE link control
CONFIG_LTE_LINK_CONTROL=y
CONFIG_LTE_AUTO_INIT_AND_CONNECT=n
CONFIG_LTE_NETWORK_MODE_LTE_M=y
CONFIG_LTE_NETWORK_USE_FALLBACK=n
# Network
CONFIG_NETWORKING=y
CONFIG_NET_NATIVE=n
CONFIG_NET_SOCKETS=y
CONFIG_NET_UDP=y
CONFIG_NET_SOCKETS_OFFLOAD=y
CONFIG_NET_SOCKETS_POSIX_NAMES=y
# Modem library
CONFIG_NRF_MODEM_LIB=y
CONFIG_NRF_MODEM_LIB_TRACE_ENABLED=n
# Heap and stacks
CONFIG_HEAP_MEM_POOL_SIZE=2048
CONFIG_MAIN_STACK_SIZE=4096
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
Last updated