samples: net: latmon: latency monitor tool
Supports the EVL/Xenomai4 benchmarking tool as described in the
documentation. The benchmarking tool is accessed via the latmon service.
This code uses the J2 socket on FRDMk64-F:
PIN_20: tx pulse to SUT
PIN_18: rx ack from SUT
The client code running on the SUT shall monitor the falling edge of
PIN_20.
Example usage from the latmus client running Xenomai4:
$ latmus -I gpiochip2,23,falling-edge \
-O gpiochip2,21 -g"histogram" \
-z broadcast
Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com>
This commit is contained in:
parent
8c0c4bdace
commit
f9eeefa6e0
7
samples/net/latmon/CMakeLists.txt
Normal file
7
samples/net/latmon/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(latmon)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
||||
13
samples/net/latmon/Kconfig
Normal file
13
samples/net/latmon/Kconfig
Normal file
@ -0,0 +1,13 @@
|
||||
# Private config options for Latmon Sample app
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright (c) 2025 Jorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com>
|
||||
|
||||
mainmenu "Latmon Sample application"
|
||||
|
||||
config LATMON_LOOPBACK_CALIBRATION
|
||||
bool "Run the sample code in calibration mode"
|
||||
default n
|
||||
help
|
||||
Run Latmon in calibration mode.
|
||||
|
||||
source "Kconfig.zephyr"
|
||||
190
samples/net/latmon/README.rst
Normal file
190
samples/net/latmon/README.rst
Normal file
@ -0,0 +1,190 @@
|
||||
.. zephyr:code-sample:: latmon-client
|
||||
:name: Latmon Client
|
||||
:relevant-api: latmon
|
||||
|
||||
Measures delta time between GPIO events and reports the latency metrics via latmon to the latmus
|
||||
service executing on the SUT.
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
This project provides tools to measure the worst-case response time of a system under test (SUT) to
|
||||
GPIO events using:
|
||||
|
||||
- **Latmon**:
|
||||
|
||||
Runs on a Zephyr-based board to generate and monitor GPIO events while collecting metrics
|
||||
|
||||
- **Latmus**:
|
||||
|
||||
Runs on the SUT to respond to the falling edge of input GPIO event, displaying the latency metrics
|
||||
and generate histogram data.
|
||||
|
||||
This project is part of the open-source initiative
|
||||
`EVL Project - Latmus GPIO Response Time <https://evlproject.org/core/benchmarks/#latmus-gpio-response-time>`_.
|
||||
|
||||
The main program is designed to monitor latency using GPIO pins on a Zephyr-based system. It generates a
|
||||
pulse signal on a GPIO pin and measures the time it takes for the SUT (executing Latmus) to respond to
|
||||
it.
|
||||
|
||||
The SUT must be running Latmus to capture the latency metrics and histogram information reported over the
|
||||
network. The program uses LEDs to indicate the different states, such as DHCP binding(red), waiting for the
|
||||
Latmus connection (blue) and sampling (green).
|
||||
|
||||
Why Not Just Use a Timer?
|
||||
=========================
|
||||
|
||||
Timer tests miss external factors like GPIO signals, hardware, and interrupt handling.
|
||||
Latmon and Latmus simulate real-world scenarios, capturing end-to-end latency metrics.
|
||||
This ensures accurate assessment of real-time responsiveness across the entire system.
|
||||
|
||||
- **Real-Time Thread Testing**:
|
||||
|
||||
Evaluates how a user-space thread processes external interrupts.
|
||||
|
||||
- **End-to-End Latency Measurement**:
|
||||
|
||||
Captures delays from hardware, drivers, and user-space threads.
|
||||
|
||||
- **Versatile Platform Support**:
|
||||
|
||||
Works on EVL, PREEMPT_RT, and other platforms.
|
||||
|
||||
Code Structure
|
||||
==============
|
||||
|
||||
The Latmon sample application is divided into two main components:
|
||||
|
||||
- **Application Logic** (:zephyr_file:`samples/net/latmon/src/main.c`):
|
||||
|
||||
This file contains the application logic for Latmon.
|
||||
It initializes networking, provides the instrumentation mechanism and handles LED indicators for the
|
||||
different states.
|
||||
|
||||
- **Library** (:zephyr_file:`subsys/net/lib/latmon/latmon.c`):
|
||||
|
||||
This file provides reusable functions and abstractions for latency monitoring via Latmus.
|
||||
It includes the core logic for reporting latency metrics and histogram data.
|
||||
|
||||
Requirements
|
||||
************
|
||||
|
||||
- **Zephyr-Compatible Board**:
|
||||
|
||||
A board with external GPIO support and an IPv4 network interface (e.g., FRDM-K64F).
|
||||
|
||||
- **System under Test**:
|
||||
|
||||
A system with external GPIO pins running the Latmus service and an IPv4 network interface.
|
||||
|
||||
- **Network Connection**:
|
||||
|
||||
A DHCP server for IP assignment.
|
||||
|
||||
- **Physical Connection**:
|
||||
|
||||
GPIO wires connecting the Zephyr board to the SUT and both systems connected to the network.
|
||||
|
||||
Setup and Usage
|
||||
***************
|
||||
|
||||
- **Flash Latmon onto the Zephyr board**:
|
||||
|
||||
The application will connect to the network and wait for a connection from the SUT. The application
|
||||
will use DHCP to obtain an IPv4 address.
|
||||
|
||||
- **Connect GPIO pins for transmit (Zephyr to SUT) and receive (SUT to Zephyr)**
|
||||
|
||||
On **FRDM-K64F**, the sample code uses the **Arduino header J2**, ``pin 20`` for transmit the pulse to
|
||||
the SUT and ``pin 18`` to receive the acknowledgment from the SUT.
|
||||
|
||||
- **Run Latmus on the SUT**
|
||||
|
||||
Request the appropriate options with `Latmus <https://evlproject.org/core/testing/#latmus-program>`_. Users
|
||||
can for example modify the sampling period with the ``-p`` option or generate historgram data for
|
||||
postprocessing with the ``-g`` option,
|
||||
|
||||
- **Monitor results from the SUT**
|
||||
|
||||
Latmus will report latency figures and, if requested, generate the histogram data file.
|
||||
|
||||
- **Calibrating the Latmus latencies: CONFIG_LATMON_LOOPBACK_CALIBRATION**:
|
||||
|
||||
Users can connect the GPIO pins in loopback mode (transmit to ack) and build the Latmon sample application with
|
||||
CONFIG_LATMON_LOOPBACK_CALIBRATION enabled. When connecting to Latmus in this configuration, Latmus is providing
|
||||
a calibration value that can be used to adjust the final latencies.
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
On the host and to build and flash the Zephyr FRDM-K64F board with the Latmon sample:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
user@host:~$ west build -b frdm_k64f samples/net/latmon
|
||||
user@host:~$ west flash
|
||||
|
||||
On the SUT running on Linux, latmus **MUST** track the falling edge of the signal:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
root@target:~$ latmus -I gpiochip2,23,falling-edge -O gpiochip2,21 -z -g"histogram" "broadcast"
|
||||
|
||||
Monitoring both consoles, you should see the following:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
[00:00:03.311,000] <inf> phy_mc_ksz8081: PHY 0 is up
|
||||
[00:00:03.311,000] <inf> phy_mc_ksz8081: PHY (0) Link speed 100 Mb, full duplex
|
||||
[00:00:03.312,000] <inf> eth_nxp_enet_mac: Link is up
|
||||
*** Booting Zephyr OS build v4.1.0-3337-g886443a190b1 ***
|
||||
[00:00:03.313,000] <inf> sample_latmon: DHCPv4: binding...
|
||||
[00:00:03.313,000] <inf> latmon: Latmon server thread priority: 14
|
||||
[00:00:10.964,000] <inf> net_dhcpv4: Received: 192.168.1.58
|
||||
[00:00:10.964,000] <inf> sample_latmon: Listening on 192.168.1.58
|
||||
[00:00:30.966,000] <inf> latmon: Waiting for Latmus ...
|
||||
[00:00:31.356,000] <inf> latmon: Monitor thread priority: -16
|
||||
[00:00:31.356,000] <inf> latmon: monitoring started:
|
||||
[00:00:31.356,000] <inf> latmon: - samples per period: 1000
|
||||
[00:00:31.356,000] <inf> latmon: - period: 1000 usecs
|
||||
[00:00:31.356,000] <inf> latmon: - histogram cells: 200
|
||||
[00:00:31.393,000] <inf> latmon: Transfer thread priority: 14
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
root@target:~$ latmus -I gpiochip2,23,falling-edge -O gpiochip2,21 -Z -g"histogram" broadcast
|
||||
Received broadcast message: 192.168.1.58
|
||||
warming up on CPU0 (not isolated)...
|
||||
connecting to latmon at 192.168.1.58:2306...
|
||||
RTT| 00:00:16 (oob-gpio, 1000 us period, priority 98, CPU0-noisol)
|
||||
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
|
||||
RTD| 26.375| 30.839| 33.508| 0| 0| 26.375| 33.508
|
||||
RTD| 26.333| 30.801| 37.633| 0| 0| 26.333| 37.633
|
||||
RTD| 26.375| 30.801| 31.966| 0| 0| 26.333| 37.633
|
||||
RTD| 26.375| 30.911| 49.675| 0| 0| 26.333| 49.675
|
||||
RTD| 26.333| 30.830| 41.658| 0| 0| 26.333| 49.675
|
||||
RTD| 26.375| 31.107| 59.216| 0| 0| 26.333| 59.216
|
||||
RTD| 26.333| 30.767| 30.925| 0| 0| 26.333| 59.216
|
||||
RTD| 26.333| 30.781| 41.616| 0| 0| 26.333| 59.216
|
||||
RTD| 26.375| 30.768| 32.925| 0| 0| 26.333| 59.216
|
||||
RTD| 26.375| 30.768| 37.633| 0| 0| 26.333| 59.216
|
||||
|
||||
On completion and from your host, retrieve the histogram file from the SUT, and generate a plot (a PNG file) using
|
||||
gnuplot:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
user@host:~$ gnuplot plot_data.gp
|
||||
|
||||
The ``plot_data.gp`` script should look like this for a file named ``histogram``:
|
||||
|
||||
.. code-block:: gnuplot
|
||||
|
||||
set terminal pngcairo size 800,600
|
||||
set output 'plot.png'
|
||||
set title "Data Plot"
|
||||
set xlabel "Latency (usec)"
|
||||
set ylabel "Sample Count"
|
||||
set grid
|
||||
set style data linespoints
|
||||
plot 'histogram' using 1:2 with linespoints title "Data Points"
|
||||
12
samples/net/latmon/boards/frdm_k64f.overlay
Normal file
12
samples/net/latmon/boards/frdm_k64f.overlay
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Copyright (c) 2025 Jorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com>
|
||||
*/
|
||||
|
||||
/ {
|
||||
zephyr,user {
|
||||
pulse_gpios = <&gpioe 24 GPIO_ACTIVE_HIGH>;
|
||||
ack_gpios = <&gpioe 25 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
22
samples/net/latmon/prj.conf
Normal file
22
samples/net/latmon/prj.conf
Normal file
@ -0,0 +1,22 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright (c) 2025 Jorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com>
|
||||
|
||||
CONFIG_POSIX_API=y
|
||||
|
||||
# General config
|
||||
CONFIG_LOG=y
|
||||
CONFIG_GPIO=y
|
||||
|
||||
# Networking config
|
||||
CONFIG_NETWORKING=y
|
||||
CONFIG_NET_DHCPV4=y
|
||||
CONFIG_NET_IPV4=y
|
||||
CONFIG_NET_LOG=y
|
||||
CONFIG_NET_TCP=y
|
||||
|
||||
# Latmon config
|
||||
CONFIG_NET_LATMON=y
|
||||
CONFIG_LATMON_LOG_LEVEL_DBG=y
|
||||
|
||||
# Heap for Latmon
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=8192
|
||||
14
samples/net/latmon/sample.yaml
Normal file
14
samples/net/latmon/sample.yaml
Normal file
@ -0,0 +1,14 @@
|
||||
sample:
|
||||
description: Latency Benchmarking Tool
|
||||
name: Latmon sample app
|
||||
common:
|
||||
harness: net
|
||||
tags:
|
||||
- net
|
||||
- latmon
|
||||
tests:
|
||||
sample.net.latmon:
|
||||
build_only: true
|
||||
platform_allow:
|
||||
- frdm_k64f
|
||||
depends_on: eth
|
||||
271
samples/net/latmon/src/main.c
Normal file
271
samples/net/latmon/src/main.c
Normal file
@ -0,0 +1,271 @@
|
||||
/*
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Copyright (c) 2025 Jorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com>
|
||||
*/
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(sample_latmon, LOG_LEVEL_DBG);
|
||||
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/net/latmon.h>
|
||||
#include <zephyr/net/socket.h>
|
||||
#include <zephyr/spinlock.h>
|
||||
#include <zephyr/sys/atomic.h>
|
||||
/*
|
||||
* Blink Control
|
||||
* DHCP: red
|
||||
* waiting for connection: blue
|
||||
* sampling: green
|
||||
*/
|
||||
#define LED_WAIT_PERIOD 1000000
|
||||
#define LED_DHCP_PERIOD 500000
|
||||
#define LED_RUN_PERIOD 200000
|
||||
|
||||
#define BLINK_THREAD_PRIORITY K_IDLE_PRIO
|
||||
#define BLINK_STACK_SIZE 4096
|
||||
static K_THREAD_STACK_DEFINE(blink_stack, BLINK_STACK_SIZE);
|
||||
|
||||
static const struct gpio_dt_spec pulse =
|
||||
GPIO_DT_SPEC_GET_OR(DT_PATH(zephyr_user), pulse_gpios, {0});
|
||||
static const struct gpio_dt_spec ack =
|
||||
GPIO_DT_SPEC_GET_OR(DT_PATH(zephyr_user), ack_gpios, {0});
|
||||
|
||||
static K_SEM_DEFINE(ack_event, 0, 1);
|
||||
|
||||
#define DHCP_DONE (atomic_test_bit(&dhcp_done, 0) == true)
|
||||
#define SET_DHCP_DONE atomic_set_bit(&dhcp_done, 0)
|
||||
static atomic_val_t dhcp_done;
|
||||
|
||||
static struct k_spinlock lock;
|
||||
|
||||
static void gpio_ack_handler(const struct device *port,
|
||||
struct gpio_callback *cb,
|
||||
gpio_port_pins_t pins)
|
||||
{
|
||||
k_sem_give(&ack_event);
|
||||
}
|
||||
|
||||
static int configure_measurement_hardware(void)
|
||||
{
|
||||
static struct gpio_callback gpio_cb = { };
|
||||
int ret = 0;
|
||||
|
||||
if (!gpio_is_ready_dt(&pulse) || !gpio_is_ready_dt(&ack)) {
|
||||
LOG_ERR("GPIO device not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(&pulse, GPIO_OUTPUT_HIGH);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("failed configuring pulse pin");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(&ack, GPIO_INPUT);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("failed configuring ack pin");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_LATMON_LOOPBACK_CALIBRATION)
|
||||
/*
|
||||
* Connect GPIO pins in loopback mode for validation (tx to ack)
|
||||
* On FRDM_K64F, Latmus will show around 3.2 usec of latency.
|
||||
*
|
||||
* You can then use these values to adjust the reported latencies (ie,
|
||||
* subtract the loopback latency from the measured latencies).
|
||||
*/
|
||||
ret = gpio_pin_interrupt_configure_dt(&ack, GPIO_INT_EDGE_FALLING);
|
||||
#else
|
||||
ret = gpio_pin_interrupt_configure_dt(&ack, GPIO_INT_EDGE_RISING);
|
||||
#endif
|
||||
if (ret < 0) {
|
||||
LOG_ERR("failed configuring ack pin interrupt");
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpio_init_callback(&gpio_cb, gpio_ack_handler, BIT(ack.pin));
|
||||
|
||||
ret = gpio_add_callback_dt(&ack, &gpio_cb);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("failed adding ack pin callback");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void blink(void*, void*, void*)
|
||||
{
|
||||
const struct gpio_dt_spec led_run =
|
||||
GPIO_DT_SPEC_GET_OR(DT_ALIAS(led0), gpios, {0});
|
||||
const struct gpio_dt_spec led_wait =
|
||||
GPIO_DT_SPEC_GET_OR(DT_ALIAS(led1), gpios, {0});
|
||||
const struct gpio_dt_spec led_dhcp =
|
||||
GPIO_DT_SPEC_GET_OR(DT_ALIAS(led2), gpios, {0});
|
||||
const struct gpio_dt_spec *led = &led_dhcp, *tmp = NULL;
|
||||
uint32_t period = LED_DHCP_PERIOD;
|
||||
|
||||
if (gpio_is_ready_dt(&led_run)) {
|
||||
gpio_pin_configure_dt(&led_run, GPIO_OUTPUT_INACTIVE);
|
||||
}
|
||||
|
||||
if (gpio_is_ready_dt(&led_wait)) {
|
||||
gpio_pin_configure_dt(&led_wait, GPIO_OUTPUT_INACTIVE);
|
||||
}
|
||||
|
||||
if (gpio_is_ready_dt(&led_dhcp)) {
|
||||
gpio_pin_configure_dt(&led_dhcp, GPIO_OUTPUT_INACTIVE);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
k_usleep(period);
|
||||
if (DHCP_DONE) {
|
||||
led = net_latmon_running() ? &led_run : &led_wait;
|
||||
}
|
||||
|
||||
if (tmp && led != tmp) {
|
||||
gpio_pin_set_dt(tmp, 0);
|
||||
}
|
||||
|
||||
if (!gpio_is_ready_dt(led)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (led == &led_wait) {
|
||||
period = LED_WAIT_PERIOD;
|
||||
}
|
||||
|
||||
if (led == &led_run) {
|
||||
period = LED_RUN_PERIOD;
|
||||
}
|
||||
|
||||
gpio_pin_toggle_dt(led);
|
||||
tmp = led;
|
||||
}
|
||||
gpio_pin_set_dt(led, 0);
|
||||
}
|
||||
|
||||
static k_tid_t start_led_blinking_thread(struct k_thread *blink_thread,
|
||||
k_thread_entry_t blink_thread_func)
|
||||
{
|
||||
return k_thread_create(blink_thread, blink_stack, BLINK_STACK_SIZE,
|
||||
(k_thread_entry_t)blink_thread_func,
|
||||
NULL, NULL, NULL,
|
||||
BLINK_THREAD_PRIORITY, 0, K_NO_WAIT);
|
||||
}
|
||||
|
||||
/* Raw ticks */
|
||||
#define CALCULATE_DELTA(ack, pulse) \
|
||||
((ack) < (pulse) ? \
|
||||
(~(pulse) + 1 + (ack)) : ((ack) - (pulse)))
|
||||
|
||||
static int measure_latency_cycles(uint32_t *delta)
|
||||
{
|
||||
k_spinlock_key_t key;
|
||||
uint32_t tx = 0;
|
||||
uint32_t rx = 0;
|
||||
int ret = 0;
|
||||
|
||||
/* Remove spurious events */
|
||||
k_sem_reset(&ack_event);
|
||||
|
||||
/* Generate a falling edge pulse to the DUT */
|
||||
key = k_spin_lock(&lock);
|
||||
if (gpio_pin_set_dt(&pulse, 0)) {
|
||||
k_spin_unlock(&lock, key);
|
||||
LOG_ERR("Failed to set pulse pin");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
tx = k_cycle_get_32();
|
||||
k_spin_unlock(&lock, key);
|
||||
|
||||
/* Wait for a rising edge from the Latmus controlled DUT */
|
||||
if (k_sem_take(&ack_event, K_MSEC(1)) == 0) {
|
||||
rx = k_cycle_get_32();
|
||||
/* Measure the cycles */
|
||||
*delta = CALCULATE_DELTA(rx, tx);
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
out:
|
||||
if (gpio_pin_set_dt(&pulse, 1)) {
|
||||
LOG_ERR("Failed to clear pulse pin");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct net_if *iface = net_if_get_default();
|
||||
struct k_thread blink_thread;
|
||||
static k_tid_t blink_tid;
|
||||
int client, socket = 0;
|
||||
int ret = 0;
|
||||
|
||||
/* Prepare the instrumentation */
|
||||
if (configure_measurement_hardware() < 0) {
|
||||
LOG_ERR("Failed to configure the measurement hardware");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Start visual indicators - dhcp/blue, waiting/red, running/green */
|
||||
blink_tid = start_led_blinking_thread(&blink_thread, blink);
|
||||
if (!blink_tid) {
|
||||
LOG_WRN("Failed to start led blinking thread");
|
||||
}
|
||||
|
||||
/* Get a valid ip */
|
||||
LOG_INF("DHCPv4: binding...");
|
||||
net_dhcpv4_start(iface);
|
||||
for (;;) {
|
||||
ret = net_mgmt_event_wait(NET_EVENT_IPV4_DHCP_BOUND, NULL,
|
||||
NULL, NULL, NULL, K_SECONDS(10));
|
||||
if (ret == -ETIMEDOUT) {
|
||||
LOG_WRN("DHCPv4: binding timed out, retrying...");
|
||||
continue;
|
||||
}
|
||||
if (ret < 0) {
|
||||
LOG_ERR("DHCPv4: binding failed, aborting...");
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
SET_DHCP_DONE;
|
||||
|
||||
/* Get a socket to the Latmus port */
|
||||
socket = net_latmon_get_socket(NULL);
|
||||
if (socket < 0) {
|
||||
LOG_ERR("Failed to get a socket to latmon (errno %d)", socket);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
/* Wait for Latmus to connect */
|
||||
client = net_latmon_connect(socket,
|
||||
&iface->config.dhcpv4.requested_ip);
|
||||
if (client < 0) {
|
||||
if (client == -EAGAIN) {
|
||||
continue;
|
||||
}
|
||||
LOG_ERR("Failed to connect to latmon");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Provide latency data until Latmus closes the connection */
|
||||
net_latmon_start(client, measure_latency_cycles);
|
||||
}
|
||||
out:
|
||||
k_thread_abort(blink_tid);
|
||||
close(socket);
|
||||
|
||||
return ret;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user