A gear lever signal that reads 3 doesn't tell you much. Your signal database usually
knows that 3 means DRIVE, and RemotiveStudio and the Python libraries can use that
knowledge. This post shows where named values live and how to work with them in both.
What named values are
Many signals don't carry a measurement. They carry a state: a door is open or closed, a gear is in park or drive, a lamp is off, on or failing. On the bus these states are plain integers, and the signal database maps each integer to a name. In a DBC file this is the value table for the signal; ARXML and LDF have their own ways of describing the same thing. Think of it as an enum attached to a signal.
RemotiveLabs calls these mappings named values. They come straight from the signal databases your topology references (DBC, ARXML, LDF, Fibex, see the supported file formats), so you don't define them anywhere else. If the database has them, you can use them.
Finding named values in RemotiveStudio
The quickest way to see what a database defines is the Signal view in RemotiveStudio:
- Open the file tree with Files and click your
.instance.yaml,.platform.yaml, or a database file directly. - Click the bar-chart icon in the segmented control at the top of the topology viewer.
- Find the frame you care about. The search bar filters both frames and signals.
- Click the frame row to expand its signals. Each signal shows its unit, min/max, factor and offset, receivers, and its named values.
The first time you open the Signal view, RemotiveStudio indexes the signal databases, so give it a moment on large ARXML files. Today the Signal view covers CAN and LIN signals.
This is also a good way to check a database before you write code against it. If you
expect GearPosition to have named values and the Signal view shows none, the database
you're using doesn't have them, and no code will fix that.
Reading named values from Python
The RemotiveBroker Python API
exposes the mapping on every SignalInfo in two directions: named_values maps raw
integers to names, and value_names maps names back to integers. Here is a small script,
adapted from the API docs, that prints both for one signal. The DriverCan namespace and
the GearData.GearPosition signal are examples; use your own.
import asyncio
from remotivelabs.broker import BrokerClient
async def main() -> None:
async with BrokerClient(url="http://127.0.0.1:50051") as broker_client:
info = await broker_client.get_signal_info("GearData.GearPosition", "DriverCan")
if info is None:
raise SystemExit("Signal not found in DriverCan")
print(info.named_values) # raw value -> name, e.g. {0: "PARK", 3: "DRIVE"}
print(info.value_names) # name -> raw value, e.g. {"PARK": 0, "DRIVE": 3}
if __name__ == "__main__":
asyncio.run(main())
If you're not sure which namespaces exist on a running topology, list them first:
remotive broker signals namespaces --url http://localhost:50051
When you subscribe, you can have the client decode values for you. Pass
decode_named_values=True to subscribe_frames, and integer values that have a mapping
arrive as their names in frame.signals:
stream = await broker_client.subscribe_frames(
("DriverCan", ["GearData"]),
decode_named_values=True,
)
async for frame in stream:
print(frame.signals) # {"GearData.GearPosition": "DRIVE", ...}
To write a state, look up the raw value with value_names and publish that integer:
from remotivelabs.broker import WriteSignal
await broker_client.publish(
("DriverCan", [WriteSignal(name="GearData.GearPosition", value=info.value_names["PARK"])]),
)
The same lookup works when you set restbus signals with RestbusSignalConfig.set(...).
If you write behavioral models or tests with the
RemotiveTopology framework,
you're using the same broker client underneath, so SignalInfo.named_values and
value_names are available there too.
Common pitfalls
- The value type changes. With
decode_named_values=True, a signal that used to be anintbecomes astr. Code that compares with== 3or does arithmetic on the value silently stops matching. Pick one style per script and stick to it. - Not every value has a name. Only integers that appear in the mapping are decoded.
A value outside the table, such as a reserved or error code, still arrives as an
int, so handle both types, or look values up yourself withinfo.named_values.get(value, value). - Decoding is off by default.
subscribe_framesdoesn't decode unless you ask, and the frame handlers in the RemotiveTopology framework take adecode_named_valuesargument that is also off by default. If you see numbers where you expected names, check this first. - Names belong to a database. Two databases can map the same signal differently, for
example a channel DBC and an ECU extract. Check the Signal view for the topology you
actually run, and look names up with
value_namesinstead of hard-coding the integers. - Typos fail late.
info.value_names["Park"]raises aKeyErrorwhen the database saysPARK. Copy names from the Signal view rather than from memory.
Named values are a small feature, but they make logs, dashboards and test assertions much easier to read. For more on the APIs, see APIs and client libraries.