Repository navigation
Feature Request: Expose Device Setting and Network Mapping Internally #264
Description
Problem
When working with python_ics, retrieving network-specific settings requires consumers to maintain device-specific mappings that duplicate information already known by the library.
For example, the following simple task:
Display the TqSeg1 value for DWCAN_02 and DWCAN_08
requires application code to maintain:
- A mapping from DeviceSettingType → settings structure name.
- A mapping from settings structure type → network-to-channel enumeration.
setting_map = {
e_device_settings_type.DeviceFire2SettingsType: "cyan",
e_device_settings_type.DeviceRADGigastarSettingsType: "radgigastar",
e_device_settings_type.DeviceRADMoon2SettingsType: "radmoon2",
e_device_settings_type.DeviceVCAN412SettingsType: "vcan412",
e_device_settings_type.DeviceFire3SettingsType: "fire3",
e_device_settings_type.DeviceRed2SettingsType: "red2",
# More devices...
}
channel_order_b = (1, 8, *range(2, 8), *range(9, 17))
SettingMapA = Enum("SettingMap", [f"DWCAN_{channel:02}" for channel in range(1, 17)])
SettingMapB = IntEnum(
"SettingMap", [f"DWCAN_{channel:02}" for channel in channel_order_b]
)
device_settings_to_netid_map = {
ics.svcan412_settings.svcan412_settings: SettingMapA,
ics.s_fire3_settings.s_fire3_settings: SettingMapB,
ics.s_red2_settings.s_red2_settings: SettingMapA,
ics.srad_gigastar_settings.srad_gigastar_settings: SettingMapB,
# More devices...
}This logic is required before we can even locate the appropriate CAN channel settings.
Why This Is Problematic
Applications that support multiple Intrepid devices must:
- Hard-code device-specific mappings.
- Duplicate logic that already exists internally.
- Update mappings whenever new device types are introduced.
- Reverse-engineer channel ordering differences between devices.
This creates unnecessary maintenance burden and makes it difficult to write device-agnostic tooling.
Expected Behavior
The library should provide a built-in mechanism to resolve network identifiers to the corresponding settings object.
Example ideas:
channel_settings = ics.get_network_settings(
device,
"DWCAN_02",
)or
channel_settings = settings.get_network("DWCAN_02")allowing consumers to access:
print(channel_settings.TqSeg1)without needing to know:
- The underlying settings structure type.
- The channel numbering scheme.
- Device-specific network ordering rules.
Current Example
Below is a complete example showing the amount of custom mapping currently required to read TqSeg1 from DWCAN_02 and DWCAN_08.
Example code
# /// script
# dependencies = [
# "python_ics>=1!26.3",
# ]
# ///
from enum import Enum, IntEnum
import ics
from ics.structures.s_device_settings import s_device_settings
from ics.structures.e_device_settings_type import e_device_settings_type
setting_map = {
e_device_settings_type.DeviceFire2SettingsType: "cyan",
e_device_settings_type.DeviceRADGigastarSettingsType: "radgigastar",
e_device_settings_type.DeviceRADMoon2SettingsType: "radmoon2",
e_device_settings_type.DeviceVCAN412SettingsType: "vcan412",
e_device_settings_type.DeviceFire3SettingsType: "fire3",
e_device_settings_type.DeviceRed2SettingsType: "red2",
}
channel_order_b = (1, 8, *range(2, 8), *range(9, 17))
SettingMapA = Enum("SettingMap", [f"DWCAN_{channel:02}" for channel in range(1, 17)])
SettingMapB = IntEnum(
"SettingMap", [f"DWCAN_{channel:02}" for channel in channel_order_b]
)
device_settings_to_netid_map = {
ics.svcan412_settings.svcan412_settings: SettingMapA,
ics.s_fire3_settings.s_fire3_settings: SettingMapB,
ics.s_red2_settings.s_red2_settings: SettingMapA,
ics.srad_gigastar_settings.srad_gigastar_settings: SettingMapB,
}
def get_device_specific_settings(s: s_device_settings) -> object:
if s.DeviceSettingType not in setting_map:
raise KeyError(
f"Error: {s.DeviceSettingType} is not a known type in setting_map"
)
return getattr(s.Settings, setting_map[s.DeviceSettingType])
def main():
devices = ics.find_devices()
for device in devices:
ics.open_device(device)
print(
f"Opened Device {device} (Open Client handles: {device.NumberOfClients})..."
)
try:
print("Loading default settings...")
ics.load_default_settings(device)
print("Reading settings...")
settings = ics.get_device_settings(device)
device_specific_settings = get_device_specific_settings(settings)
net_id_map = device_settings_to_netid_map.get(
type(device_specific_settings), Enum("SettingMap", [])
)
# Trying to display TqSeg1 for DWCAN_02 and DWCAN_08
for net_id in ("DWCAN_02", "DWCAN_08"):
if net_id not in net_id_map.__members__:
print(f"{net_id} not found in net_id_map.")
continue
channel_id = net_id_map[net_id].value
channel_attr = f"can{channel_id}"
if not hasattr(device_specific_settings, channel_attr):
print(f"{net_id} not found in device settings.")
continue
channel_settings = getattr(device_specific_settings, channel_attr)
print(f"{net_id} ({channel_attr}) TqSeg1: {channel_settings.TqSeg1}")
finally:
print(f"Closing Device {device}...")
device.close()
if __name__ == "__main__":
main()Benefit
Providing this mapping internally would:
- Simplify device-independent applications.
- Reduce duplicated code across projects.
- Eliminate fragile hard-coded mappings.
- Improve forward compatibility with future device types.
- Make the API easier to discover and use.
Question: Is there already an internal API capable of resolving a network identifier (e.g. DWCAN_02) to the corresponding settings structure, or would the maintainers be open to exposing this functionality?
Activity
pierreluctg commentedon Oct 7, 2026
FYI @drebbe-intrepid
drebbe-intrepid commentedon Oct 21, 2026
@pierreluctg sorry for the late reply but this is a huge pain point of icsneo40 and python_ics. icsneopy essentially takes care of this for us already so I recommend switching to that. I'm going to close this out as won't fix so we aren't reproducing the work already done in icsneopy.