samples/net: Add cellular modem sample
This commit adds a sample application which demonstrates how to use the new driver and modules. The sample uses power management to turn on the modem, uses network management to wait for L4 connected, then uses DNS to get the IP of the server running the python script found in the server folder, which echoes back data recevied to it. A packet containing psudo random data is then sent to the server, which the echoes it back. To validate the capability of the driver to restart the modem, the modem is restarted, and the packet is sent again. The server is hosted by linode, and uses the domain name test-endpoint.com Signed-off-by: Bjarki Arge Andreasen <baa@trackunit.com>
This commit is contained in:
parent
bfdd382ffc
commit
c0c9d6f7d6
12 changed files with 693 additions and 0 deletions
8
samples/net/cellular_modem/CMakeLists.txt
Normal file
8
samples/net/cellular_modem/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(cellular_modem)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
57
samples/net/cellular_modem/README.rst
Normal file
57
samples/net/cellular_modem/README.rst
Normal file
|
@ -0,0 +1,57 @@
|
|||
.. _cellular_modem_sample:
|
||||
|
||||
Cellular Modem Sample
|
||||
########################
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
This sample consists of a simple application which powers on
|
||||
the modem, brings up the net interface, then sends a packet
|
||||
with pseudo random data to the endpoint test-endpoint.com,
|
||||
which is a publicly hosted server which runs the Python
|
||||
script found in the server folder. DNS is used to look
|
||||
up the IP of test-endpoint.com.
|
||||
|
||||
Notes
|
||||
*****
|
||||
|
||||
This sample uses the devicetree alias modem to identify
|
||||
the modem instance to use. The sample also presumes that
|
||||
the modem driver creates the only network interface.
|
||||
|
||||
Setup
|
||||
*****
|
||||
|
||||
Start by setting up the devicetree with the required
|
||||
devicetree node:
|
||||
|
||||
.. code-block:: devicetree
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
modem = &modem;
|
||||
};
|
||||
};
|
||||
|
||||
&usart2 {
|
||||
pinctrl-0 = <&usart2_tx_pa2 &usart2_rx_pa3 &usart2_rts_pa1 &usart2_cts_pa0>;
|
||||
pinctrl-names = "default";
|
||||
current-speed = <115200>;
|
||||
hw-flow-control;
|
||||
status = "okay";
|
||||
|
||||
modem: modem {
|
||||
compatible = "quectel,bg9x";
|
||||
mdm-power-gpios = <&gpioe 2 GPIO_ACTIVE_HIGH>;
|
||||
mdm-reset-gpios = <&gpioe 3 GPIO_ACTIVE_HIGH>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
Next, the UART API must be specified using ``CONFIG_UART_INTERRUPT_DRIVEN=y`` or
|
||||
``CONFIG_UART_ASYNC_API=y``. The driver doesn't support UART polling.
|
||||
|
||||
Lastly, the APN must be configured using ``CONFIG_MODEM_CELLULAR_APN=""``.
|
5
samples/net/cellular_modem/boards/b_u585i_iot02a.conf
Normal file
5
samples/net/cellular_modem/boards/b_u585i_iot02a.conf
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Copyright (c) 2023, Bjarki Arge Andreasen
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
CONFIG_UART_ASYNC_API=y
|
||||
CONFIG_MODEM_CELLULAR_APN="internet"
|
38
samples/net/cellular_modem/boards/b_u585i_iot02a.overlay
Normal file
38
samples/net/cellular_modem/boards/b_u585i_iot02a.overlay
Normal file
|
@ -0,0 +1,38 @@
|
|||
/ {
|
||||
aliases {
|
||||
modem-uart = &usart2;
|
||||
modem = &modem;
|
||||
};
|
||||
};
|
||||
|
||||
&gpioh {
|
||||
misc_fixed_usart2 {
|
||||
gpio-hog;
|
||||
gpios = <13 GPIO_ACTIVE_HIGH>;
|
||||
output-high;
|
||||
};
|
||||
};
|
||||
|
||||
&gpdma1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* BG95 */
|
||||
&usart2 {
|
||||
pinctrl-0 = <&usart2_tx_pa2 &usart2_rx_pa3 &usart2_rts_pa1 &usart2_cts_pa0>;
|
||||
pinctrl-names = "default";
|
||||
current-speed = <115200>;
|
||||
hw-flow-control;
|
||||
|
||||
dmas = <&gpdma1 0 27 STM32_DMA_PERIPH_TX
|
||||
&gpdma1 1 26 STM32_DMA_PERIPH_RX>;
|
||||
dma-names = "tx", "rx";
|
||||
|
||||
status = "okay";
|
||||
|
||||
modem: modem {
|
||||
compatible = "quectel,bg95";
|
||||
mdm-power-gpios = <&gpioe 2 GPIO_ACTIVE_HIGH>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
24
samples/net/cellular_modem/prj.conf
Normal file
24
samples/net/cellular_modem/prj.conf
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Copyright (c) 2023 Bjarki Arge Andreasen
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Networking
|
||||
CONFIG_NETWORKING=y
|
||||
CONFIG_NET_NATIVE=y
|
||||
CONFIG_NET_L2_PPP=y
|
||||
CONFIG_NET_IPV4=y
|
||||
CONFIG_NET_UDP=y
|
||||
CONFIG_NET_SOCKETS=y
|
||||
|
||||
# DNS
|
||||
CONFIG_DNS_RESOLVER=y
|
||||
CONFIG_NET_L2_PPP_OPTION_DNS_USE=y
|
||||
|
||||
# Network management
|
||||
CONFIG_NET_MGMT=y
|
||||
CONFIG_NET_MGMT_EVENT=y
|
||||
CONFIG_NET_CONNECTION_MANAGER=y
|
||||
|
||||
# Modem driver
|
||||
CONFIG_MODEM=y
|
||||
CONFIG_PM_DEVICE=y
|
||||
CONFIG_MODEM_CELLULAR=y
|
13
samples/net/cellular_modem/sample.yaml
Normal file
13
samples/net/cellular_modem/sample.yaml
Normal file
|
@ -0,0 +1,13 @@
|
|||
sample:
|
||||
description: Sample for cellular modem
|
||||
name: Sample for cellular modem using native networking
|
||||
common:
|
||||
tags: cellular modem
|
||||
tests:
|
||||
sample.net.cellular_modem:
|
||||
tags: cellular modem
|
||||
filter: dt_alias_exists("modem")
|
||||
platform_allow:
|
||||
- b_u585i_iot02a
|
||||
integration_platforms:
|
||||
- b_u585i_iot02a
|
22
samples/net/cellular_modem/server/te.py
Executable file
22
samples/net/cellular_modem/server/te.py
Executable file
|
@ -0,0 +1,22 @@
|
|||
# Copyright (c) 2023, Bjarki Arge Andreasen
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import signal
|
||||
from te_udp_echo import TEUDPEcho
|
||||
from te_udp_receive import TEUDPReceive
|
||||
|
||||
udp_echo = TEUDPEcho()
|
||||
udp_receive = TEUDPReceive()
|
||||
|
||||
udp_echo.start()
|
||||
udp_receive.start()
|
||||
|
||||
print("started")
|
||||
|
||||
def terminate_handler(a, b):
|
||||
udp_echo.stop()
|
||||
udp_receive.stop()
|
||||
print("stopped")
|
||||
|
||||
signal.signal(signal.SIGTERM, terminate_handler)
|
||||
signal.signal(signal.SIGINT, terminate_handler)
|
40
samples/net/cellular_modem/server/te_udp_echo.py
Executable file
40
samples/net/cellular_modem/server/te_udp_echo.py
Executable file
|
@ -0,0 +1,40 @@
|
|||
# Copyright (c) 2023, Bjarki Arge Andreasen
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import socket
|
||||
import threading
|
||||
import select
|
||||
|
||||
class TEUDPEcho():
|
||||
def __init__(self):
|
||||
self.running = True
|
||||
self.thread = threading.Thread(target=self._target_)
|
||||
|
||||
def start(self):
|
||||
self.thread.start()
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
self.thread.join(1)
|
||||
|
||||
def _target_(self):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.setblocking(False)
|
||||
sock.bind(('0.0.0.0', 7780))
|
||||
|
||||
while self.running:
|
||||
try:
|
||||
ready_to_read, _, _ = select.select([sock], [sock], [], 0.5)
|
||||
|
||||
if not ready_to_read:
|
||||
continue
|
||||
|
||||
data, address = sock.recvfrom(4096)
|
||||
print(f'udp echo {len(data)} bytes to {address[0]}:{address[1]}')
|
||||
sock.sendto(data, address)
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
break
|
||||
|
||||
sock.close()
|
107
samples/net/cellular_modem/server/te_udp_receive.py
Executable file
107
samples/net/cellular_modem/server/te_udp_receive.py
Executable file
|
@ -0,0 +1,107 @@
|
|||
# Copyright (c) 2023, Bjarki Arge Andreasen
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import socket
|
||||
import threading
|
||||
import select
|
||||
import time
|
||||
import copy
|
||||
|
||||
class TEUDPReceiveSession():
|
||||
def __init__(self, address, timeout = 1):
|
||||
self.address = address
|
||||
self.last_packet_received_at = time.monotonic()
|
||||
self.timeout = timeout
|
||||
self.packets_received = 0
|
||||
self.packets_dropped = 0
|
||||
|
||||
def get_address(self):
|
||||
return self.address
|
||||
|
||||
def on_packet_received(self, data):
|
||||
if self._validate_packet_(data):
|
||||
self.packets_received += 1
|
||||
else:
|
||||
self.packets_dropped += 1
|
||||
|
||||
self.last_packet_received_at = time.monotonic()
|
||||
|
||||
def update(self):
|
||||
if (time.monotonic() - self.last_packet_received_at) > self.timeout:
|
||||
return (self.packets_received, self.packets_dropped)
|
||||
return None
|
||||
|
||||
def _validate_packet_(self, data: bytes) -> bool:
|
||||
prng_state = 1234
|
||||
for b in data:
|
||||
prng_state = ((1103515245 * prng_state) + 12345) % (1 << 31)
|
||||
if prng_state & 0xFF != b:
|
||||
return False
|
||||
return True
|
||||
|
||||
class TEUDPReceive():
|
||||
def __init__(self):
|
||||
self.running = True
|
||||
self.thread = threading.Thread(target=self._target_)
|
||||
self.sessions = []
|
||||
|
||||
def start(self):
|
||||
self.thread.start()
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
self.thread.join(1)
|
||||
|
||||
def _target_(self):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.setblocking(False)
|
||||
sock.bind(('0.0.0.0', 7781))
|
||||
|
||||
while self.running:
|
||||
try:
|
||||
ready_to_read, _, _ = select.select([sock], [sock], [], 0.5)
|
||||
|
||||
if not ready_to_read:
|
||||
self._update_sessions_(sock)
|
||||
continue
|
||||
|
||||
data, address = sock.recvfrom(4096)
|
||||
|
||||
print(f'udp received {len(data)} bytes -> {address[0]}:{address[1]}')
|
||||
|
||||
session = self._get_session_by_address_(address)
|
||||
session.on_packet_received(data)
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
break
|
||||
|
||||
sock.close()
|
||||
|
||||
def _get_session_by_address_(self, address) -> TEUDPReceiveSession:
|
||||
# Search for existing session
|
||||
for session in self.sessions:
|
||||
if session.get_address() == address:
|
||||
return session
|
||||
|
||||
# Create and return new session
|
||||
print(f'Created session for {address[0]}:{address[1]}')
|
||||
self.sessions.append(TEUDPReceiveSession(address, 2))
|
||||
return self.sessions[-1]
|
||||
|
||||
def _update_sessions_(self, sock):
|
||||
sessions = copy.copy(self.sessions)
|
||||
|
||||
for session in sessions:
|
||||
result = session.update()
|
||||
|
||||
if result is None:
|
||||
continue
|
||||
|
||||
response = bytes([result[0], result[1]])
|
||||
|
||||
print(f'Sending result {response} to address {session.get_address()}')
|
||||
sock.sendto(response, session.get_address())
|
||||
|
||||
print(f'Removing session for address {session.get_address()}')
|
||||
self.sessions.remove(session)
|
330
samples/net/cellular_modem/src/main.c
Normal file
330
samples/net/cellular_modem/src/main.c
Normal file
|
@ -0,0 +1,330 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Bjarki Arge Andreasen
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/net/socket.h>
|
||||
#include <zephyr/net/net_if.h>
|
||||
#include <zephyr/net/dns_resolve.h>
|
||||
#include <zephyr/pm/device.h>
|
||||
#include <zephyr/pm/device_runtime.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SAMPLE_TEST_ENDPOINT_HOSTNAME ("test-endpoint.com")
|
||||
#define SAMPLE_TEST_ENDPOINT_UDP_ECHO_PORT (7780)
|
||||
#define SAMPLE_TEST_ENDPOINT_UDP_RECEIVE_PORT (7781)
|
||||
#define SAMPLE_TEST_PACKET_SIZE (1024)
|
||||
#define SAMPLE_TEST_ECHO_PACKETS (16)
|
||||
#define SAMPLE_TEST_TRANSMIT_PACKETS (128)
|
||||
|
||||
const struct device *modem = DEVICE_DT_GET(DT_ALIAS(modem));
|
||||
|
||||
static uint8_t sample_test_packet[SAMPLE_TEST_PACKET_SIZE];
|
||||
static uint8_t sample_recv_buffer[SAMPLE_TEST_PACKET_SIZE];
|
||||
static bool sample_test_dns_in_progress;
|
||||
static struct dns_addrinfo sample_test_dns_addrinfo;
|
||||
|
||||
K_SEM_DEFINE(dns_query_sem, 0, 1);
|
||||
|
||||
static uint8_t sample_prng_random(void)
|
||||
{
|
||||
static uint32_t prng_state = 1234;
|
||||
|
||||
prng_state = ((1103515245 * prng_state) + 12345) % (1U << 31);
|
||||
return (uint8_t)(prng_state & 0xFF);
|
||||
}
|
||||
|
||||
static void init_sample_test_packet(void)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(sample_test_packet); i++) {
|
||||
sample_test_packet[i] = sample_prng_random();
|
||||
}
|
||||
}
|
||||
|
||||
static void sample_dns_request_result(enum dns_resolve_status status, struct dns_addrinfo *info,
|
||||
void *user_data)
|
||||
{
|
||||
if (sample_test_dns_in_progress == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (status != DNS_EAI_INPROGRESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
sample_test_dns_in_progress = false;
|
||||
sample_test_dns_addrinfo = *info;
|
||||
k_sem_give(&dns_query_sem);
|
||||
}
|
||||
|
||||
static int sample_dns_request(void)
|
||||
{
|
||||
static uint16_t dns_id;
|
||||
int ret;
|
||||
|
||||
sample_test_dns_in_progress = true;
|
||||
ret = dns_get_addr_info(SAMPLE_TEST_ENDPOINT_HOSTNAME,
|
||||
DNS_QUERY_TYPE_A,
|
||||
&dns_id,
|
||||
sample_dns_request_result,
|
||||
NULL,
|
||||
19000);
|
||||
if (ret < 0) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (k_sem_take(&dns_query_sem, K_SECONDS(20)) < 0) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sample_echo_packet(struct sockaddr *ai_addr, socklen_t ai_addrlen)
|
||||
{
|
||||
int ret;
|
||||
int socket_fd;
|
||||
uint32_t packets_sent = 0;
|
||||
uint32_t send_start_ms;
|
||||
uint32_t echo_received_ms;
|
||||
uint32_t accumulated_ms = 0;
|
||||
|
||||
printk("Opening UDP socket\n");
|
||||
|
||||
socket_fd = zsock_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (socket_fd < 0) {
|
||||
printk("Failed to open socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printk("Socket opened\n");
|
||||
|
||||
if (ai_addr->sa_family == AF_INET) {
|
||||
net_sin(ai_addr)->sin_port = htons(SAMPLE_TEST_ENDPOINT_UDP_ECHO_PORT);
|
||||
} else if (ai_addr->sa_family == AF_INET6) {
|
||||
net_sin6(ai_addr)->sin6_port = htons(SAMPLE_TEST_ENDPOINT_UDP_ECHO_PORT);
|
||||
} else {
|
||||
printk("Unsupported address family\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < SAMPLE_TEST_ECHO_PACKETS; i++) {
|
||||
send_start_ms = k_uptime_get_32();
|
||||
|
||||
ret = zsock_sendto(socket_fd, sample_test_packet, sizeof(sample_test_packet), 0,
|
||||
ai_addr, ai_addrlen);
|
||||
|
||||
if (ret < sizeof(sample_test_packet)) {
|
||||
printk("Failed to send sample test packet\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = zsock_recv(socket_fd, sample_recv_buffer, sizeof(sample_recv_buffer), 0);
|
||||
if (ret != sizeof(sample_test_packet)) {
|
||||
printk("Echoed sample test packet has incorrect size\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
echo_received_ms = k_uptime_get_32();
|
||||
|
||||
if (memcmp(sample_test_packet, sample_recv_buffer,
|
||||
sizeof(sample_recv_buffer)) != 0) {
|
||||
printk("Echoed sample test packet data mismatch\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
packets_sent++;
|
||||
accumulated_ms += echo_received_ms - send_start_ms;
|
||||
|
||||
printk("Echo transmit time %ums\n", echo_received_ms - send_start_ms);
|
||||
}
|
||||
|
||||
printk("Successfully sent %u packets of %u packets\n", packets_sent,
|
||||
SAMPLE_TEST_ECHO_PACKETS);
|
||||
|
||||
printk("Average time per echo: %u ms\n",
|
||||
accumulated_ms / packets_sent);
|
||||
|
||||
printk("Close UDP socket\n");
|
||||
|
||||
ret = zsock_close(socket_fd);
|
||||
if (ret < 0) {
|
||||
printk("Failed to close socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int sample_transmit_packets(struct sockaddr *ai_addr, socklen_t ai_addrlen)
|
||||
{
|
||||
int ret;
|
||||
int socket_fd;
|
||||
uint32_t packets_sent = 0;
|
||||
uint32_t packets_received;
|
||||
uint32_t packets_dropped;
|
||||
uint32_t send_start_ms;
|
||||
uint32_t send_end_ms;
|
||||
|
||||
printk("Opening UDP socket\n");
|
||||
|
||||
socket_fd = zsock_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (socket_fd < 0) {
|
||||
printk("Failed to open socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printk("Socket opened\n");
|
||||
|
||||
if (ai_addr->sa_family == AF_INET) {
|
||||
net_sin(ai_addr)->sin_port = htons(SAMPLE_TEST_ENDPOINT_UDP_RECEIVE_PORT);
|
||||
} else if (ai_addr->sa_family == AF_INET6) {
|
||||
net_sin6(ai_addr)->sin6_port = htons(SAMPLE_TEST_ENDPOINT_UDP_RECEIVE_PORT);
|
||||
} else {
|
||||
printk("Unsupported address family\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printk("Sending %u packets\n", SAMPLE_TEST_TRANSMIT_PACKETS);
|
||||
send_start_ms = k_uptime_get_32();
|
||||
for (uint32_t i = 0; i < SAMPLE_TEST_TRANSMIT_PACKETS; i++) {
|
||||
ret = zsock_sendto(socket_fd, sample_test_packet, sizeof(sample_test_packet), 0,
|
||||
ai_addr, ai_addrlen);
|
||||
|
||||
if (ret < sizeof(sample_test_packet)) {
|
||||
printk("Failed to send sample test packet\n");
|
||||
break;
|
||||
}
|
||||
|
||||
packets_sent++;
|
||||
}
|
||||
send_end_ms = k_uptime_get_32();
|
||||
|
||||
printk("Awaiting response from server\n");
|
||||
ret = zsock_recv(socket_fd, sample_recv_buffer, sizeof(sample_recv_buffer), 0);
|
||||
if (ret != 2) {
|
||||
printk("Invalid response\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
packets_received = sample_recv_buffer[0];
|
||||
packets_dropped = sample_recv_buffer[1];
|
||||
printk("Server received %u packets\n", packets_received);
|
||||
printk("Server dropped %u packets\n", packets_dropped);
|
||||
printk("Time elapsed sending packets %ums\n", send_end_ms - send_start_ms);
|
||||
printk("Throughput %u bytes/s\n",
|
||||
((SAMPLE_TEST_PACKET_SIZE * SAMPLE_TEST_TRANSMIT_PACKETS) * 1000) /
|
||||
(send_end_ms - send_start_ms));
|
||||
|
||||
printk("Close UDP socket\n");
|
||||
ret = zsock_close(socket_fd);
|
||||
if (ret < 0) {
|
||||
printk("Failed to close socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
uint32_t raised_event;
|
||||
const void *info;
|
||||
size_t info_len;
|
||||
int ret;
|
||||
|
||||
init_sample_test_packet();
|
||||
|
||||
printk("Powering on modem\n");
|
||||
pm_device_action_run(modem, PM_DEVICE_ACTION_RESUME);
|
||||
|
||||
printk("Bring up network interface\n");
|
||||
ret = net_if_up(net_if_get_default());
|
||||
if (ret < 0) {
|
||||
printk("Failed to bring up network interface\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printk("Waiting for L4 connected\n");
|
||||
ret = net_mgmt_event_wait_on_iface(net_if_get_default(),
|
||||
NET_EVENT_L4_CONNECTED, &raised_event, &info,
|
||||
&info_len, K_SECONDS(120));
|
||||
|
||||
if (ret != 0) {
|
||||
printk("L4 was not connected in time\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printk("Waiting for DNS server added\n");
|
||||
ret = net_mgmt_event_wait_on_iface(net_if_get_default(),
|
||||
NET_EVENT_DNS_SERVER_ADD, &raised_event, &info,
|
||||
&info_len, K_SECONDS(10));
|
||||
|
||||
printk("Performing DNS lookup of %s\n", SAMPLE_TEST_ENDPOINT_HOSTNAME);
|
||||
ret = sample_dns_request();
|
||||
if (ret < 0) {
|
||||
printk("DNS query failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = sample_echo_packet(&sample_test_dns_addrinfo.ai_addr,
|
||||
sample_test_dns_addrinfo.ai_addrlen);
|
||||
|
||||
if (ret < 0) {
|
||||
printk("Failed to send echo\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = sample_transmit_packets(&sample_test_dns_addrinfo.ai_addr,
|
||||
sample_test_dns_addrinfo.ai_addrlen);
|
||||
|
||||
if (ret < 0) {
|
||||
printk("Failed to send packets\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printk("Restart modem\n");
|
||||
ret = pm_device_action_run(modem, PM_DEVICE_ACTION_SUSPEND);
|
||||
if (ret != 0) {
|
||||
printk("Failed to power down modem\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pm_device_action_run(modem, PM_DEVICE_ACTION_RESUME);
|
||||
ret = net_mgmt_event_wait_on_iface(net_if_get_default(),
|
||||
NET_EVENT_L4_CONNECTED, &raised_event, &info,
|
||||
&info_len, K_SECONDS(60));
|
||||
|
||||
if (ret != 0) {
|
||||
printk("L4 was not connected in time\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = sample_echo_packet(&sample_test_dns_addrinfo.ai_addr,
|
||||
sample_test_dns_addrinfo.ai_addrlen);
|
||||
|
||||
if (ret < 0) {
|
||||
printk("Failed to send echo after restart\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = net_if_down(net_if_get_default());
|
||||
if (ret < 0) {
|
||||
printk("Failed to bring down network interface\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printk("Powering down modem\n");
|
||||
ret = pm_device_action_run(modem, PM_DEVICE_ACTION_SUSPEND);
|
||||
if (ret != 0) {
|
||||
printk("Failed to power down modem\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printk("Sample complete\n");
|
||||
return 0;
|
||||
}
|
12
samples/net/gsm_modem/boards/b_u585i_iot02a.conf
Normal file
12
samples/net/gsm_modem/boards/b_u585i_iot02a.conf
Normal file
|
@ -0,0 +1,12 @@
|
|||
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||
CONFIG_GSM_MUX=y
|
||||
CONFIG_UART_MUX=y
|
||||
CONFIG_MODEM_GSM_APN="internet"
|
||||
CONFIG_MAIN_STACK_SIZE=8192
|
||||
CONFIG_MODEM_GSM_QUECTEL=y
|
||||
CONFIG_MODEM_SHELL=n
|
||||
CONFIG_NET_MGMT_EVENT_INFO=y
|
||||
CONFIG_NET_MGMT_EVENT_MONITOR=y
|
||||
CONFIG_NET_MGMT_EVENT_MONITOR_AUTO_START=y
|
||||
CONFIG_NET_LOG=y
|
||||
CONFIG_NET_MGMT_EVENT_LOG_LEVEL_DBG=y
|
37
samples/net/gsm_modem/boards/b_u585i_iot02a.overlay
Normal file
37
samples/net/gsm_modem/boards/b_u585i_iot02a.overlay
Normal file
|
@ -0,0 +1,37 @@
|
|||
/ {
|
||||
aliases {
|
||||
modem-uart = &usart2;
|
||||
modem = &modem;
|
||||
};
|
||||
};
|
||||
|
||||
&gpioh {
|
||||
misc_fixed_usart2 {
|
||||
gpio-hog;
|
||||
gpios = <13 GPIO_ACTIVE_HIGH>;
|
||||
output-high;
|
||||
};
|
||||
};
|
||||
|
||||
&gpdma1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* BG95 */
|
||||
&usart2 {
|
||||
pinctrl-0 = <&usart2_tx_pa2 &usart2_rx_pa3 &usart2_rts_pa1 &usart2_cts_pa0>;
|
||||
pinctrl-names = "default";
|
||||
current-speed = <115200>;
|
||||
hw-flow-control;
|
||||
|
||||
dmas = <&gpdma1 0 27 STM32_DMA_PERIPH_TX
|
||||
&gpdma1 1 26 STM32_DMA_PERIPH_RX>;
|
||||
dma-names = "tx", "rx";
|
||||
|
||||
status = "okay";
|
||||
|
||||
modem: modem {
|
||||
compatible = "zephyr,gsm-ppp";
|
||||
status = "okay";
|
||||
};
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue