-Add gevent rtnetlink listener for interface and IP changes.
-Refresh cached transport info immediately after network changes.
-Extend x4xx cache TTL to 300 seconds with epoch-based invalidation.
get_xport_info() enumerates network interfaces via netlink/pyudev on every
GetDeviceInfo call (~350ms, non-yielding). Since GetDeviceInfo is
unclaimed and gets flooded during discovery, this could starve claimed
RPCs past their short deadlines like 2 seconds.
Cache the result for 10s (X400_XPORT_INFO_CACHE_TTL); it's stable per
session, and init() drops the cache since IPs may change. This turns most
GetDeviceInfo calls much faster.
Add a dedicated lock for the xport_info_cache so concurrent
GetDeviceInfo calls don't race on refresh/invalidations
pb_utils.py contains several helpers to translate between
Protobuf and Python datatypes/messages including other utility
functions. This change adds a bunch of unit tests to cover
various aspects of its usage by rpc_server.py.
Update MPM GPIO handling for the updated X4xx GPIO SPI register
interface.
Require the FPGA compatibility number bump introduced with the new
SPI support so MPM does not operate against an incompatible FPGA image.
Bump MPM compat number.
Treat a RuntimeError raised while the periph manager is resetting as
transient. Log once at WARNING and abort with gRPC status UNAVAILABLE
so the client retries, instead of logging a scary ERROR.
Real runtime errors still log ERROR and abort when periph manager
object is live.
usrp_hwd runs all gRPC greenlets on a single gevent hub, so any
non-yielding C call blocks every other RPC. Under a uhd_find_devices
discovery flood, the GetDeviceInfo interface enumeration run long enough
And may starve most claimed RPC past its default 2s client deadline,
causing "Deadline Exceeded" failures.
Three places that this commit optimizes, all in net.py:
- get_local_ip_addrs() used pyroute2 IPDB, which spawns helper threads
and mirrors the full link/addr/route/neighbour tables on every call
(~100s of ms, non-yielding) --> Replace it with a single stateless
IPRoute get_addr() dump. Keep IFA_LOCAL (falling back to IFA_ADDRESS)
so the returned set matches IPDB's behaviour, including point-to-point
links.
- get_link_speed() used to create a new pyudev.Context() per interface,
which forks on creation, tripping gRPC's fork handlers. gRPC then
freezes all workder threads and restarts after fork is done. Fix is to
reuse one PID-guarded pyudev context per process.
- get_valid_interfaces() did an O(N) netlink round-trip per interface.
This stalls gRPC server. --> Dump all links and IPv4 addresses once
and filter in Python.
IPRoute stays per-call: it opens its own netlink socket and does not
fork, so there is no shared state to lock.
We see this warning about lingering references during UHD operations
like image load even if they are not. We did some testing to verify.
It seems the garbage collector could take some time to remove these
reference. But the warning here could be misleading. Hence, removed.
UHD hosts <4.10 speak mprpc and unconditionally connect to the RPC port
(49601) of any device they discover. When they reach a gRPC-based MPM
device, the protocol mismatch crashes uhd_find_device.
UHd host 4.10, prevents this by using rpc_version key from discovery
response and skips RPC attempt if mprpc device found during
uhd_find_devices.
This change moves the RPC port to 49602. Now, old UHD <4.10 hosts can
still discover both mprpc and grpc devices. But their mprpc connection
attempt on 49601 during uhd_find_devices is refused by grpc device
(running on new rpc port 49602) and is marked as not reachable instead
of crashing.
The main RPC channel can sit idle for a long time (e.g. an interactive
Python session) while only the claim-loop channel sees traffic. Without
keepalive, gRPC self-closes the idle transport (~30 min) and the next
RPC fails re-establishing within its per-call deadline.
With this change the client now pings every 30 s to keep the channel
warm, and the server is configured to accept that cadence instead of
replying GOAWAY "too_many_pings".
The MPM gRPC server runs on a single-threaded gevent hub. gRPC's BDP
(bandwidth-estimation) probe fires repeatedly while the reclaim loop
keeps the link busy, and its ACK must return within grpcio's short,
RTT-derived internal BDP deadline. Any blocking hardware register read
(e.g. a ClkMgr PLL-lock poll) stalls all socket I/O on the hub until it
returns; , but these polls also run periodically in steady state.
When a stall outlasts the BDP deadline the server sends GOAWAY
"ping_timeout" and drops the transport. The fix is to disable BDP on
the server. The default flow-control window is fine on the LAN link,
so this costs nothing here. BDP is left enabled on the client, whose
native-threaded stack never freezes.
no_claim decorator was recently added in method
get_device_info_dyn() but it was missed to get imported from
usrp_mpm.rpc_utils which causes device initialize failure.
- Verify signature in case the device does not support customizable
FPGA (just as sanity check before actual loading the bitstream).
- Extract the bitstream from the bootgen generated .bin file
otherwise.
Provide the following two functions by wrapping the "bootgen"
command line tool:
verify: verify the validity of the signature of the .bin file.
extract_bitstream: extract the FPGA bitstream from the .bin file.
This works if the .bin file includes the FPGA bitstream as a
single partition.
add helper to clear pending db ADCSelfCal host tasks
clear any existing ADC SelfCal tasks in init() when
skip_adc_selfcal is enabled
prevent restart_tiles() from re-scheduling
ADC SelfCal tasks when skip_adc_selfcal=1
log when ADC self-cal task scheduling is intentionally skipped
host:
Replace the msgpack-RPC (rpclib) client with a gRPC-based
implementation. Add auto-generated C++ client and Python bindings
from protobuf definitions. Remove rpclib dependency and integrate
FindgRPC into CMake.
mpm:
Replace the msgpack-RPC server with a gRPC server generated from
protobuf definitions. Add pb_utils.py for type conversion between
Python and protobuf. Update rpc_server.py to dispatch calls via
gRPC stubs. Update mpm_shell to use gRPC. Replace pyudev with sysfs
scan in uio device discovery.
Bump MPM compatibility number to 7.0 and RPC version to 2.
This change requires new depedencies. E.g. for Ubuntu 24.04 or 25.10:
libgrpc++-dev, libprotobuf-dev, protobuf-compiler-grpc, python3-grpcio
Introduce HwmonTempSensors (sysfs_hwmon.py) and refactor
SysfsThermalSensors (sysfs_thermal.py) to enumerate available sensors
once at construction time and cache device references in a sensor_map
dict, avoiding repeated udev context creation and device-tree walks on
every readout.
HwmonTempSensors supports the cros-ec hwmon subsystem and accepts a
sensor_list parameter to discover both temp and fan sensors. A new
read_fan_sensor_value() method is added alongside the existing
read_thermal_sensor_value(). Multiple subsystems (hwmon, iio) and
sensor formats are supported via a read_sysfs_sensors_value() utility.
SysfsThermalSensors is extended to support multiple subsystems (IIO
and thermal) and a data_probe parameter for flexible attribute reading.
A read_fan_sensor_value() method is added to match the hwmon interface.
Both classes expose the same read_thermal_sensor_value(sensor_names,
reduce_fn) interface, making them interchangeable at the call site.
All affected peripheral managers are updated:
- E320: updated to use the new sensor abstraction pattern
- N3xx: refactored temp and fan sensor methods for hwmon/thermal backends
- X4xx: unified _temp_fan_sensors handle with hwmon/thermal dispatch,
add missing HwmonTempSensors import
- E310: add dynamic MB temperature sensor type detection instead of
hardcoding "jc-42.4-temp", fixing usrp_list_sensors compatibility
A _hwmon_based_sensors flag at init time selects the correct backend
for fan and temperature reads on all platforms.
The i2c-adapter subsystem was meant as a temporary compatibility
layer. The recommended option always was to rely on i2c-dev
subsystem only. With commit 7e722083fc the i2c-adapter subsystem
was finally removed from Linux kernel 6.12.
The logic for resolving the i2c-dev device node was changed
accordingly.
This change also adopts all occurances in the code where the I2C
bus or device node is resolved to use resolving by devicetree
symbol. E.g. in n3xx.py, the N32X QSFP I2C node was resolved by
devicetree label before.
Overall, two functions are now provided by sys_utils.i2c_dev:
- dt_symbol_get_i2c_bus: Get the I2C bus (as pyudev.Device) for
a given device tree symbol. This function is used if the
returned value is further used for filtering devices using
udev, e.g. searching for certain devices on the same I2C bus.
- dt_symbol_get_i2c_device_node: Get the i2c-dev device node
(e.g. "/dev/i2c-0") for a given device tree symbol. This function
is used in cases where only the device node is of interest, e.g.
when passing it to a C/C++ library.
The recent change in 2e7ec47 exposed a new corner case:
- Assume two consecutive sessions with external clock and otherwise
identical device args. In this case, the second session would usually
start without forcing a re-init, because we assume the clocks are
still fine.
- Now what if the external ref clock glitches between sessions, i.e.,
when no UHD is running? In this case, the `spll_unlock_event` flag
would never be set
- Because the reference lock check was implicitly sticky before the
change, this would still cause a forced re-init in the past, but not
anymore
This commit calls get_ref_stable() during session initialization to
scoop up any sticky bits that occurred between the last successful UHD
session and the new one. The ref-stable sensor state will be
reconfigured during device initialization, so this does not lose any
information.
When the SPLL loses reference lock and then re-locks to the reference,
its R-dividers will be out of sync. This change allows a new argument to
the set_sync_source() API call to resynchronize SPLL R-dividers to the
PPS flank. This is not a supported operation, and it may leave the FPGA
in an unknown state. For this reason, this option should only be
exercised by experienced users who know exactly which consequences this
may have.
To call this feature, use the reset_spll_r_divider key in the sync args:
```python
my_usrp.set_sync_source("reset_spll_r_divider=1")
```
If a reset was necessary and the R-divider reset was successful, it will
be necessary to also resynchronize timestamps between devices and
timekeepers.
With the most recent changes, Boost.Thread and all Boost date/time
libraries are no longer required. This updates the CMake and Debian
files to reflect those changes.
This adds a new sensor called `ref_stable` to the X4xx series. Unlike
`ref_locked`, which only checks the current ref-lock status, this will
also query the sticky bits of the LMK04832 lock-detect circuitry, and
then clear them. This allows checking if ref-lock was lost any time
between queries to the `ref_stable` sensor (unlike the `ref_locked`
sensor, which queries the current ref-lock status).
This changes the LMK04832 class to only optionally (and not always)
check the sticky LD_LOST flags in the 0x182 lock-detect register of the
LMK04832. As a result, the ref_locked sensor will now only return the
current lock status of this PLL, and the ref-locked LED