ekfsm 1.4.0a42__tar.gz → 1.4.0a60__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ekfsm might be problematic. Click here for more details.
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/PKG-INFO +4 -4
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/devenv.lock +2 -2
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/reference/ekfsm.rst +11 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/boards/oem/ekf/z1010.yaml +8 -1
- ekfsm-1.4.0a60/ekfsm/core/connections.py +19 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/core/sysfs.py +32 -2
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/button.py +15 -0
- ekfsm-1.4.0a60/ekfsm/devices/buttonArray.py +206 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/colorLed.py +33 -2
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/coretemp.py +26 -3
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/eeprom.py +4 -4
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/generic.py +41 -12
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/io4edge.py +19 -3
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/ledArray.py +20 -2
- ekfsm-1.4.0a60/ekfsm/devices/pixelDisplay.py +137 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/pmbus.py +8 -4
- ekfsm-1.4.0a60/ekfsm/devices/smbios.py +60 -0
- ekfsm-1.4.0a60/ekfsm/devices/thermal_humidity.py +78 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/watchdog.py +26 -2
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/pyproject.toml +4 -4
- ekfsm-1.4.0a60/tests/cctv.py +80 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/cctv.yaml +1 -1
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sq3-only.py +11 -8
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/uv.lock +58 -267
- ekfsm-1.4.0a42/ekfsm/devices/buttonArray.py +0 -104
- ekfsm-1.4.0a42/ekfsm/devices/pixelDisplay.py +0 -88
- ekfsm-1.4.0a42/ekfsm/devices/smbios.py +0 -42
- ekfsm-1.4.0a42/ekfsm/devices/thermal_humidity.py +0 -49
- ekfsm-1.4.0a42/tests/cctv.py +0 -41
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/.env +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/.envrc +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/.flake8 +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/.gitattributes +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/.gitignore +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/.gitlab-ci.yml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/.readthedocs.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/.vscode/launch.json +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/.vscode/settings.json +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/GitVersion.yml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/LICENSE.md +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/README.md +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/devenv.nix +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/devenv.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/.gitignore +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/Makefile +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/requirements.txt +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/_static/devices.drawio.png +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/_static/devices.drawio.svg +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/_static/ekfsm_system.drawio.png +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/_static/ekfsm_system.drawio.svg +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/boards/ekf/ccu.rst +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/boards/ekf/sc5-festival.rst +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/boards/ekf/sc9-toccata.rst +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/boards/ekf/se5-club.rst +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/boards/ekf/sn4-djembe.rst +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/boards/ekf/snippets/cpci_inventory.rst +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/boards/ekf/spv-mystic.rst +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/boards/ekf/sq1-track.rst +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/boards/ekf/sq3-quartet.rst +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/boards/ekf/sur-uart.rst +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/boards/hitron/hdrc-300s.rst +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/boards.rst +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/conf.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/index.rst +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/intro.rst +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/reference/index.rst +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/docs/source/reference/systemconfig.rst +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/__init__.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/boards/oem/ekf/ccu.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/boards/oem/ekf/sc5-festival.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/boards/oem/ekf/sc9-toccata.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/boards/oem/ekf/se5-club.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/boards/oem/ekf/sn4-djembe.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/boards/oem/ekf/spv-mystic.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/boards/oem/ekf/sq1-track.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/boards/oem/ekf/sq3-quartet.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/boards/oem/ekf/srf-fan.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/boards/oem/ekf/sur-uart.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/boards/oem/hitron/hdrc-300s.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/cli.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/config.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/core/__init__.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/core/components.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/core/probe.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/core/slots.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/core/utils.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/__init__.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/ekf_ccu_uc.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/ekf_sur_led.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/gpio.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/iio.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/iio_thermal_humidity.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/imu.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/mux.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/smbus.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/devices/utils.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/exceptions.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/lock.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/log.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/py.typed +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/simctrl.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/system.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/ekfsm/utils.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/hack/bringup_zip_i2c_devs.sh +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/scripts/modify-acpi-table.sh +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/__init__.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/basic_sim.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/ccu-test.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/ccu_wokwi_sim.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/data/cfg_simple.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/locking/lock_tester.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/locking/test_lock.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/props.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/run.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sc5-hitron-only.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/SQ3.png +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/__init__.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/bus/i2c/drivers/at24/.keep +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/bus/i2c/drivers/pca953x/.keep +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/bus/i2c/drivers/pca954x/.keep +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/class/hwmon/hwmon2/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/class/hwmon/hwmon2/temp1_input +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-10/firmware_node/adr +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-10/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-10/new_device +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-11/firmware_node/adr +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-11/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-11/new_device +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-12/firmware_node/adr +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-12/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-12/new_device +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-14/firmware_node/adr +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-14/i2c-PRP0002:01/firmware_node/description +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-14/i2c-PRP0002:01/gpiochip1/dev +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-14/i2c-PRP0002:01/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-14/i2c-PRP0002:02/eeprom +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-14/i2c-PRP0002:02/firmware_node/description +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-14/i2c-PRP0002:02/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-14/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-14/new_device +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-15/firmware_node/adr +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-15/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-15/new_device +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-16/firmware_node/adr +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-16/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-16/new_device +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-17/firmware_node/adr +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-17/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-17/new_device +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-9/firmware_node/adr +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-9/i2c-PRP0001:01/firmware_node/description +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-9/i2c-PRP0001:01/gpiochip1/dev +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-9/i2c-PRP0001:01/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-9/i2c-PRP0001:02/eeprom +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-9/i2c-PRP0001:02/firmware_node/description +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-9/i2c-PRP0001:02/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-9/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-9/new_device +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-PRP0001:00/firmware_node/description +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-PRP0001:00/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-PRP0001:03/firmware_node/description +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-PRP0001:03/hwmon/hwmon99/curr1_input +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-PRP0001:03/hwmon/hwmon99/curr2_input +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-PRP0001:03/hwmon/hwmon99/in1_input +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-PRP0001:03/hwmon/hwmon99/in2_input +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-PRP0001:03/hwmon/hwmon99/model +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-PRP0001:03/hwmon/hwmon99/revision +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-PRP0001:03/hwmon/hwmon99/serial +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-PRP0001:03/hwmon/hwmon99/temp1_input +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-PRP0001:03/hwmon/hwmon99/vendor +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-PRP0001:03/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-PRP0002:00/firmware_node/description +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/i2c-PRP0002:00/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:15.1/i2c_designware.2/i2c-1/new_device +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:1f.4/i2c-7/7-0057/eeprom +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/pci0000:00/0000:00:1f.4/i2c-7/7-0057/name +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/devices/virtual/dmi/id/board_version +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/kernel/debug/pmbus/hwmon99/status0_input +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/sys/kernel/debug/pmbus/hwmon99/status1_input +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/test_system.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sim/test_system_inconsistent.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/sq3-only.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/srf-fan-test.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/srf-fan-test.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/test_config.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/test_module_schema.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/test_sim-ccu-eeprom.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/test_sim1.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/test_sim2.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/zip2-ccu-only.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/zip2-comp1.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/zip2-comp1_smoke.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/zip2-comp2.yaml +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/zip2-comp2_smoke.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/zip2_ccu_exp.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/zip2_ccu_imu.py +0 -0
- {ekfsm-1.4.0a42 → ekfsm-1.4.0a60}/tests/zip2_psu.py +0 -0
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ekfsm
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.0a60
|
|
4
4
|
Summary: The EKF System Management Library (ekfsm) is a sensor monitoring suite for Compact PCI Serial devices.
|
|
5
5
|
Author-email: Jan Jansen <jan@ekf.de>, Klaus Popp <klaus.popp@ci4rail.com>, Felix Päßler <fp@ekf.de>
|
|
6
|
-
Requires-Python: >=3.
|
|
6
|
+
Requires-Python: >=3.12
|
|
7
7
|
Requires-Dist: anytree
|
|
8
8
|
Requires-Dist: click>=8.0.1
|
|
9
9
|
Requires-Dist: crcmod
|
|
10
10
|
Requires-Dist: gpiod>=2.1.0
|
|
11
11
|
Requires-Dist: hexdump
|
|
12
|
-
Requires-Dist: io4edge-client>=
|
|
12
|
+
Requires-Dist: io4edge-client>=2.0.3
|
|
13
13
|
Requires-Dist: ipdb>=0.13.13
|
|
14
14
|
Requires-Dist: more-itertools
|
|
15
15
|
Requires-Dist: munch
|
|
16
16
|
Requires-Dist: pillow
|
|
17
|
-
Requires-Dist: protobuf
|
|
17
|
+
Requires-Dist: protobuf>=6.32.1
|
|
18
18
|
Requires-Dist: schema>=0.7.7
|
|
19
19
|
Requires-Dist: smbus2
|
|
20
20
|
Requires-Dist: termcolor>=3.0.1
|
|
@@ -75,10 +75,10 @@
|
|
|
75
75
|
]
|
|
76
76
|
},
|
|
77
77
|
"locked": {
|
|
78
|
-
"lastModified":
|
|
78
|
+
"lastModified": 1759523803,
|
|
79
79
|
"owner": "cachix",
|
|
80
80
|
"repo": "pre-commit-hooks.nix",
|
|
81
|
-
"rev": "
|
|
81
|
+
"rev": "cfc9f7bb163ad8542029d303e599c0f7eee09835",
|
|
82
82
|
"type": "github"
|
|
83
83
|
},
|
|
84
84
|
"original": {
|
|
@@ -82,6 +82,17 @@ SMBIOS
|
|
|
82
82
|
~~~~~~
|
|
83
83
|
.. automodule:: ekfsm.devices.smbios
|
|
84
84
|
|
|
85
|
+
IO4Edge Devices
|
|
86
|
+
---------------
|
|
87
|
+
|
|
88
|
+
.. automodule:: ekfsm.devices.io4edge
|
|
89
|
+
.. automodule:: ekfsm.devices.ledArray
|
|
90
|
+
.. automodule:: ekfsm.devices.colorLed
|
|
91
|
+
.. automodule:: ekfsm.devices.buttonArray
|
|
92
|
+
.. automodule:: ekfsm.devices.button
|
|
93
|
+
.. automodule:: ekfsm.devices.thermal_humidity
|
|
94
|
+
.. automodule:: ekfsm.devices.watchdog
|
|
95
|
+
|
|
85
96
|
Base Classes and Utilities
|
|
86
97
|
--------------------------
|
|
87
98
|
|
|
@@ -42,7 +42,7 @@ children:
|
|
|
42
42
|
# - write: write_customer_area
|
|
43
43
|
# - read: customer_area
|
|
44
44
|
- device_type: IO4Edge
|
|
45
|
-
name: "
|
|
45
|
+
name: "I4E"
|
|
46
46
|
provides:
|
|
47
47
|
management:
|
|
48
48
|
- identify_firmware
|
|
@@ -85,3 +85,10 @@ children:
|
|
|
85
85
|
- kick
|
|
86
86
|
- device_type: ThermalHumidity
|
|
87
87
|
name: "th"
|
|
88
|
+
- device_type: ButtonArray
|
|
89
|
+
name: "buttons"
|
|
90
|
+
service_suffix: "gpios"
|
|
91
|
+
children:
|
|
92
|
+
- device_type: Button
|
|
93
|
+
name: "eject"
|
|
94
|
+
channel_id: 2
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from contextlib import contextmanager
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Connectable:
|
|
5
|
+
|
|
6
|
+
def __init__(self, client=None):
|
|
7
|
+
self._client = client
|
|
8
|
+
self._connected = False
|
|
9
|
+
|
|
10
|
+
@contextmanager
|
|
11
|
+
def connect(self):
|
|
12
|
+
if not self._connected:
|
|
13
|
+
client = self._client(self.service_addr, command_timeout=self.timeout)
|
|
14
|
+
self._connected = True
|
|
15
|
+
try:
|
|
16
|
+
yield client
|
|
17
|
+
finally:
|
|
18
|
+
client.close()
|
|
19
|
+
del client
|
|
@@ -166,7 +166,7 @@ class SysfsDevice(MutableMapping):
|
|
|
166
166
|
|
|
167
167
|
def read_int(self, attr) -> int:
|
|
168
168
|
"""
|
|
169
|
-
Read a sysfs attribute as an integer
|
|
169
|
+
Read a sysfs attribute stored as a string as an integer
|
|
170
170
|
|
|
171
171
|
Parameters
|
|
172
172
|
----------
|
|
@@ -186,7 +186,7 @@ class SysfsDevice(MutableMapping):
|
|
|
186
186
|
"""
|
|
187
187
|
try:
|
|
188
188
|
value = self.read_attr_utf8(attr).strip()
|
|
189
|
-
return int(value
|
|
189
|
+
return int(value)
|
|
190
190
|
except StopIteration as e:
|
|
191
191
|
raise SysFSError(f"'{attr}' sysfs attribute does not exist") from e
|
|
192
192
|
except SysFSError:
|
|
@@ -194,6 +194,36 @@ class SysfsDevice(MutableMapping):
|
|
|
194
194
|
except ValueError as e:
|
|
195
195
|
raise ConversionError("Failed to convert sysfs value to int") from e
|
|
196
196
|
|
|
197
|
+
def read_hex(self, attr) -> int:
|
|
198
|
+
"""
|
|
199
|
+
Read a sysfs attribute stored as a hexadecimal integer as integer
|
|
200
|
+
|
|
201
|
+
Parameters
|
|
202
|
+
----------
|
|
203
|
+
attr: str
|
|
204
|
+
The sysfs attribute to read
|
|
205
|
+
|
|
206
|
+
Returns
|
|
207
|
+
-------
|
|
208
|
+
The sysfs attribute as a hexadecimal integer
|
|
209
|
+
|
|
210
|
+
Raises
|
|
211
|
+
------
|
|
212
|
+
SysFSError
|
|
213
|
+
If the sysfs attribute does not exist
|
|
214
|
+
ConversionError
|
|
215
|
+
If the sysfs attribute could not be converted to a hexadecimal integer
|
|
216
|
+
"""
|
|
217
|
+
try:
|
|
218
|
+
value = self.read_attr_utf8(attr).strip()
|
|
219
|
+
return int(value, 16)
|
|
220
|
+
except StopIteration as e:
|
|
221
|
+
raise SysFSError(f"'{attr}' sysfs attribute does not exist") from e
|
|
222
|
+
except SysFSError:
|
|
223
|
+
raise
|
|
224
|
+
except ValueError as e:
|
|
225
|
+
raise ConversionError("Failed to convert sysfs value to hex int") from e
|
|
226
|
+
|
|
197
227
|
def read_utf8(self, attr, strip=True) -> str:
|
|
198
228
|
"""
|
|
199
229
|
Read a sysfs attribute as a UTF-8 encoded string
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
from typing import Callable
|
|
2
2
|
from ekfsm.devices.generic import Device
|
|
3
|
+
from ekfsm.log import ekfsm_logger
|
|
4
|
+
|
|
5
|
+
logger = ekfsm_logger(__name__)
|
|
3
6
|
|
|
4
7
|
|
|
5
8
|
class Button(Device):
|
|
@@ -17,12 +20,15 @@ class Button(Device):
|
|
|
17
20
|
*args,
|
|
18
21
|
**kwargs,
|
|
19
22
|
):
|
|
23
|
+
logger.debug(f"Initializing Button '{name}' on channel {channel_id}")
|
|
20
24
|
|
|
21
25
|
super().__init__(name, parent, children, abort, *args, **kwargs)
|
|
22
26
|
|
|
23
27
|
self.channel_id = channel_id
|
|
28
|
+
logger.debug(f"Button '{name}' assigned to channel {channel_id}")
|
|
24
29
|
|
|
25
30
|
self._handler: Callable | None = None
|
|
31
|
+
logger.info(f"Button '{name}' initialized on channel {channel_id}")
|
|
26
32
|
|
|
27
33
|
@property
|
|
28
34
|
def handler(self):
|
|
@@ -43,8 +49,17 @@ class Button(Device):
|
|
|
43
49
|
"""
|
|
44
50
|
if callable(func):
|
|
45
51
|
self._handler = func
|
|
52
|
+
logger.info(
|
|
53
|
+
f"Handler set for button '{self.name}' on channel {self.channel_id}"
|
|
54
|
+
)
|
|
55
|
+
logger.debug(
|
|
56
|
+
f"Handler function: {func.__name__ if hasattr(func, '__name__') else str(func)}"
|
|
57
|
+
)
|
|
46
58
|
else:
|
|
47
59
|
self._handler = None
|
|
60
|
+
logger.debug(
|
|
61
|
+
f"Handler cleared for button '{self.name}' on channel {self.channel_id}"
|
|
62
|
+
)
|
|
48
63
|
|
|
49
64
|
def __repr__(self):
|
|
50
65
|
return f"{self.name}; Channel ID: {self.channel_id}"
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
from ekfsm.devices.button import Button
|
|
3
|
+
from ekfsm.devices.generic import Device
|
|
4
|
+
from ekfsm.devices.io4edge import IO4Edge
|
|
5
|
+
from ekfsm.log import ekfsm_logger
|
|
6
|
+
from io4edge_client.binaryiotypeb import Client, Pb
|
|
7
|
+
import io4edge_client.functionblock as fb
|
|
8
|
+
|
|
9
|
+
logger = ekfsm_logger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ButtonArray(Device):
|
|
13
|
+
"""
|
|
14
|
+
Device class for handling an io4edge button array.
|
|
15
|
+
|
|
16
|
+
To read button events, call the `read` method in a separate thread.
|
|
17
|
+
|
|
18
|
+
Note
|
|
19
|
+
----
|
|
20
|
+
Button handlers are called in the context of the `read` method's thread and need to be set in the Button instances.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
name: str,
|
|
26
|
+
parent: IO4Edge,
|
|
27
|
+
children: list[Device] | None = None,
|
|
28
|
+
abort: bool = False,
|
|
29
|
+
service_suffix: str | None = None,
|
|
30
|
+
keepaliveInterval: int = 10000,
|
|
31
|
+
*args,
|
|
32
|
+
**kwargs,
|
|
33
|
+
):
|
|
34
|
+
logger.debug(
|
|
35
|
+
f"Initializing ButtonArray '{name}' with parent device {parent.deviceId}"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
Device.__init__(self, name, parent, children, abort, *args, **kwargs)
|
|
39
|
+
|
|
40
|
+
self.name = name
|
|
41
|
+
|
|
42
|
+
if service_suffix is not None:
|
|
43
|
+
self.service_suffix = service_suffix
|
|
44
|
+
logger.debug(f"Using custom service suffix: {service_suffix}")
|
|
45
|
+
else:
|
|
46
|
+
self.service_suffix = name
|
|
47
|
+
logger.debug(f"Using default service suffix: {name}")
|
|
48
|
+
|
|
49
|
+
self.service_addr = f"{parent.deviceId}-{self.service_suffix}"
|
|
50
|
+
self.timeout = keepaliveInterval / 1000 + 5
|
|
51
|
+
|
|
52
|
+
logger.info(
|
|
53
|
+
f"ButtonArray '{name}' configured with service address: {self.service_addr}"
|
|
54
|
+
)
|
|
55
|
+
logger.debug(
|
|
56
|
+
f"Keepalive interval: {keepaliveInterval}ms, timeout: {self.timeout}s"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
self.client = Client(
|
|
61
|
+
self.service_addr, command_timeout=self.timeout, connect=False
|
|
62
|
+
)
|
|
63
|
+
logger.debug(f"IO4Edge client created for service: {self.service_addr}")
|
|
64
|
+
except Exception as e:
|
|
65
|
+
logger.error(
|
|
66
|
+
f"Failed to create IO4Edge client for {self.service_addr}: {e}"
|
|
67
|
+
)
|
|
68
|
+
raise
|
|
69
|
+
|
|
70
|
+
self.subscriptionType = Pb.SubscriptionType.BINARYIOTYPEB_ON_RISING_EDGE
|
|
71
|
+
self.stream_cfg = fb.Pb.StreamControlStart(
|
|
72
|
+
bucketSamples=1, # 1 sample per bucket, also ein event pro bucket
|
|
73
|
+
keepaliveInterval=keepaliveInterval,
|
|
74
|
+
bufferedSamples=2, # 2 samples werden gepuffert
|
|
75
|
+
low_latency_mode=True, # schickt soweit moeglich sofort die Events
|
|
76
|
+
)
|
|
77
|
+
logger.debug(
|
|
78
|
+
"Stream configuration initialized with rising edge subscription and low latency mode"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# Log button children count
|
|
82
|
+
button_count = sum(1 for child in (children or []) if isinstance(child, Button))
|
|
83
|
+
logger.info(f"ButtonArray '{name}' initialized with {button_count} button(s)")
|
|
84
|
+
|
|
85
|
+
def read(self, stop_event: threading.Event | None = None, timeout: float = 1):
|
|
86
|
+
"""
|
|
87
|
+
Read all button events and dispatch to handlers.
|
|
88
|
+
|
|
89
|
+
Parameters
|
|
90
|
+
----------
|
|
91
|
+
stop_event : threading.Event, optional
|
|
92
|
+
Event to signal stopping the reading loop. If None, the loop will run indefinitely.
|
|
93
|
+
timeout : float, optional
|
|
94
|
+
Timeout for reading from the stream in seconds. Default is 0.1 seconds.
|
|
95
|
+
|
|
96
|
+
Note
|
|
97
|
+
----
|
|
98
|
+
This method blocks and should be run in a separate thread.
|
|
99
|
+
"""
|
|
100
|
+
button_channels = [
|
|
101
|
+
button for button in self.children if isinstance(button, Button)
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
if not button_channels:
|
|
105
|
+
logger.warning(
|
|
106
|
+
f"No button children found in ButtonArray '{self.name}', read operation will have no effect"
|
|
107
|
+
)
|
|
108
|
+
return
|
|
109
|
+
|
|
110
|
+
logger.info(
|
|
111
|
+
f"Starting button event reading for {len(button_channels)} buttons on '{self.name}'"
|
|
112
|
+
)
|
|
113
|
+
logger.debug(
|
|
114
|
+
f"Read timeout: {timeout}s, stop_event provided: {stop_event is not None}"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
with self.client as client:
|
|
119
|
+
logger.debug(
|
|
120
|
+
f"IO4Edge client connected to service: {self.service_addr}"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# Prepare subscription channels
|
|
124
|
+
subscribe_channels = tuple(
|
|
125
|
+
Pb.SubscribeChannel(
|
|
126
|
+
channel=button.channel_id,
|
|
127
|
+
subscriptionType=self.subscriptionType,
|
|
128
|
+
)
|
|
129
|
+
for button in button_channels
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
channel_ids = [button.channel_id for button in button_channels]
|
|
133
|
+
logger.debug(
|
|
134
|
+
f"Subscribing to {len(subscribe_channels)} button channels: {channel_ids}"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
client.start_stream(
|
|
138
|
+
Pb.StreamControlStart(subscribeChannel=subscribe_channels),
|
|
139
|
+
self.stream_cfg,
|
|
140
|
+
)
|
|
141
|
+
logger.info(
|
|
142
|
+
f"Button event stream started for ButtonArray '{self.name}'"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
event_count = 0
|
|
146
|
+
try:
|
|
147
|
+
while not (stop_event and stop_event.is_set()):
|
|
148
|
+
try:
|
|
149
|
+
_, samples = client.read_stream(timeout=timeout)
|
|
150
|
+
|
|
151
|
+
for sample in samples.samples:
|
|
152
|
+
for button in button_channels:
|
|
153
|
+
pressed = bool(
|
|
154
|
+
sample.inputs & (1 << button.channel_id)
|
|
155
|
+
)
|
|
156
|
+
if pressed:
|
|
157
|
+
event_count += 1
|
|
158
|
+
button_name = getattr(button, "name", "unnamed")
|
|
159
|
+
logger.debug(
|
|
160
|
+
f"Button press on channel {button.channel_id} ({button_name})"
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if button.handler:
|
|
164
|
+
try:
|
|
165
|
+
logger.debug(
|
|
166
|
+
f"Calling handler for button on channel {button.channel_id}"
|
|
167
|
+
)
|
|
168
|
+
button.handler()
|
|
169
|
+
except Exception as e:
|
|
170
|
+
logger.error(
|
|
171
|
+
f"Error in button handler for channel {button.channel_id}: {e}"
|
|
172
|
+
)
|
|
173
|
+
else:
|
|
174
|
+
logger.debug(
|
|
175
|
+
f"No handler set for button on channel {button.channel_id}"
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
except TimeoutError:
|
|
179
|
+
# Timeout is expected during normal operation
|
|
180
|
+
continue
|
|
181
|
+
except Exception as e:
|
|
182
|
+
logger.error(
|
|
183
|
+
f"Error reading button events from stream: {e}"
|
|
184
|
+
)
|
|
185
|
+
break
|
|
186
|
+
|
|
187
|
+
except KeyboardInterrupt:
|
|
188
|
+
logger.info(
|
|
189
|
+
f"Button reading interrupted for ButtonArray '{self.name}'"
|
|
190
|
+
)
|
|
191
|
+
finally:
|
|
192
|
+
logger.info(
|
|
193
|
+
f"Button event reading stopped for '{self.name}' after processing {event_count} events"
|
|
194
|
+
)
|
|
195
|
+
if stop_event:
|
|
196
|
+
stop_event.clear()
|
|
197
|
+
logger.debug("Stop event cleared")
|
|
198
|
+
|
|
199
|
+
except Exception as e:
|
|
200
|
+
logger.error(
|
|
201
|
+
f"Failed to establish connection or start stream for ButtonArray '{self.name}': {e}"
|
|
202
|
+
)
|
|
203
|
+
raise
|
|
204
|
+
|
|
205
|
+
def __repr__(self):
|
|
206
|
+
return f"{self.name}; Service Address: {self.service_addr}"
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
from ekfsm.devices.generic import Device
|
|
2
2
|
from ekfsm.devices.ledArray import LEDArray
|
|
3
|
+
from ekfsm.log import ekfsm_logger
|
|
3
4
|
from io4edge_client.api.colorLED.python.colorLED.v1alpha1.colorLED_pb2 import Color
|
|
4
5
|
|
|
6
|
+
logger = ekfsm_logger(__name__)
|
|
7
|
+
|
|
5
8
|
|
|
6
9
|
class ColorLED(Device):
|
|
7
10
|
"""
|
|
@@ -18,6 +21,7 @@ class ColorLED(Device):
|
|
|
18
21
|
*args,
|
|
19
22
|
**kwargs,
|
|
20
23
|
):
|
|
24
|
+
logger.debug(f"Initializing ColorLED '{name}' on channel {channel_id}")
|
|
21
25
|
|
|
22
26
|
super().__init__(name, parent, children, abort, *args, **kwargs)
|
|
23
27
|
|
|
@@ -25,6 +29,9 @@ class ColorLED(Device):
|
|
|
25
29
|
self.channel_id = channel_id
|
|
26
30
|
|
|
27
31
|
self.client = parent.client
|
|
32
|
+
logger.info(
|
|
33
|
+
f"ColorLED '{name}' initialized on channel {channel_id} with parent LEDArray"
|
|
34
|
+
)
|
|
28
35
|
|
|
29
36
|
def describe(self):
|
|
30
37
|
pass
|
|
@@ -44,7 +51,19 @@ class ColorLED(Device):
|
|
|
44
51
|
TimeoutError
|
|
45
52
|
if the command times out
|
|
46
53
|
"""
|
|
47
|
-
|
|
54
|
+
logger.debug(
|
|
55
|
+
f"Getting color LED state for '{self.name}' on channel {self.channel_id}"
|
|
56
|
+
)
|
|
57
|
+
try:
|
|
58
|
+
result = self.client.get(self.channel_id)
|
|
59
|
+
color, blink = result
|
|
60
|
+
logger.debug(f"ColorLED '{self.name}' state: color={color}, blink={blink}")
|
|
61
|
+
return result
|
|
62
|
+
except Exception as e:
|
|
63
|
+
logger.error(
|
|
64
|
+
f"Failed to get ColorLED '{self.name}' state on channel {self.channel_id}: {e}"
|
|
65
|
+
)
|
|
66
|
+
raise
|
|
48
67
|
|
|
49
68
|
def set(self, color: Color, blink: bool) -> None:
|
|
50
69
|
"""
|
|
@@ -64,7 +83,19 @@ class ColorLED(Device):
|
|
|
64
83
|
TimeoutError
|
|
65
84
|
if the command times out
|
|
66
85
|
"""
|
|
67
|
-
|
|
86
|
+
logger.info(
|
|
87
|
+
f"Setting ColorLED '{self.name}' on channel {self.channel_id}: color={color}, blink={blink}"
|
|
88
|
+
)
|
|
89
|
+
try:
|
|
90
|
+
self.client.set(self.channel_id, color, blink)
|
|
91
|
+
logger.debug(
|
|
92
|
+
f"ColorLED '{self.name}' successfully set to color={color}, blink={blink}"
|
|
93
|
+
)
|
|
94
|
+
except Exception as e:
|
|
95
|
+
logger.error(
|
|
96
|
+
f"Failed to set ColorLED '{self.name}' on channel {self.channel_id}: {e}"
|
|
97
|
+
)
|
|
98
|
+
raise
|
|
68
99
|
|
|
69
100
|
def __repr__(self):
|
|
70
101
|
return f"{self.name}; Channel ID: {self.channel_id}"
|
|
@@ -7,6 +7,9 @@ from pathlib import Path
|
|
|
7
7
|
import ekfsm.core
|
|
8
8
|
from ekfsm.core.sysfs import sysfs_root
|
|
9
9
|
from ekfsm.devices.generic import Device
|
|
10
|
+
from ekfsm.log import ekfsm_logger
|
|
11
|
+
|
|
12
|
+
logger = ekfsm_logger(__name__)
|
|
10
13
|
|
|
11
14
|
# Path to the root of the HWMON sysfs filesystem
|
|
12
15
|
HWMON_ROOT = sysfs_root() / Path("class/hwmon")
|
|
@@ -55,8 +58,16 @@ class CoreTemp(Device):
|
|
|
55
58
|
*args,
|
|
56
59
|
**kwargs,
|
|
57
60
|
):
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
logger.debug(f"Initializing CoreTemp device '{name}'")
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
dir = find_core_temp_dir(sysfs_root() / Path("class/hwmon"))
|
|
65
|
+
logger.debug(f"Found coretemp directory: {dir}")
|
|
66
|
+
self.sysfs_device = ekfsm.core.sysfs.SysfsDevice(dir, False)
|
|
67
|
+
logger.info(f"CoreTemp '{name}' initialized with sysfs device at {dir}")
|
|
68
|
+
except FileNotFoundError as e:
|
|
69
|
+
logger.error(f"Failed to initialize CoreTemp '{name}': {e}")
|
|
70
|
+
raise
|
|
60
71
|
|
|
61
72
|
super().__init__(name, parent, None, abort, *args, **kwargs)
|
|
62
73
|
|
|
@@ -69,4 +80,16 @@ class CoreTemp(Device):
|
|
|
69
80
|
int
|
|
70
81
|
The CPU temperature in degrees Celsius.
|
|
71
82
|
"""
|
|
72
|
-
|
|
83
|
+
logger.debug(f"Reading CPU temperature for CoreTemp '{self.name}'")
|
|
84
|
+
try:
|
|
85
|
+
temp_raw = self.sysfs.read_float("temp1_input")
|
|
86
|
+
temp_celsius = temp_raw / 1000
|
|
87
|
+
logger.debug(
|
|
88
|
+
f"CoreTemp '{self.name}' raw reading: {temp_raw}, temperature: {temp_celsius}°C"
|
|
89
|
+
)
|
|
90
|
+
return temp_celsius
|
|
91
|
+
except Exception as e:
|
|
92
|
+
logger.error(
|
|
93
|
+
f"Failed to read CPU temperature for CoreTemp '{self.name}': {e}"
|
|
94
|
+
)
|
|
95
|
+
raise
|
|
@@ -520,8 +520,8 @@ class EKF_EEPROM(Validatable_EEPROM, ProbeableDevice):
|
|
|
520
520
|
The date the device was manufactured.
|
|
521
521
|
"""
|
|
522
522
|
area = self._content[self._date_mft_index_start : self._date_mft_index_end]
|
|
523
|
-
encoded_mft_date = area[::-1]
|
|
524
|
-
return self._decode_date(
|
|
523
|
+
# encoded_mft_date = area[::-1]
|
|
524
|
+
return self._decode_date(area)
|
|
525
525
|
|
|
526
526
|
@validated
|
|
527
527
|
def repaired_at(self) -> date:
|
|
@@ -533,8 +533,8 @@ class EKF_EEPROM(Validatable_EEPROM, ProbeableDevice):
|
|
|
533
533
|
The most recent date the device was repaired.
|
|
534
534
|
"""
|
|
535
535
|
area = self._content[self._date_rep_index_start : self._date_rep_index_end]
|
|
536
|
-
encoded_rep_date = area[::-1]
|
|
537
|
-
return self._decode_date(
|
|
536
|
+
# encoded_rep_date = area[::-1]
|
|
537
|
+
return self._decode_date(area)
|
|
538
538
|
|
|
539
539
|
@validated
|
|
540
540
|
def write_repaired_at(self, date: date) -> None:
|
|
@@ -63,7 +63,9 @@ class Device(SysTree):
|
|
|
63
63
|
try:
|
|
64
64
|
func = list(interface.values())[0]
|
|
65
65
|
except IndexError:
|
|
66
|
-
raise ConfigError(
|
|
66
|
+
raise ConfigError(
|
|
67
|
+
f"{self.name}: No function given for interface {name}."
|
|
68
|
+
)
|
|
67
69
|
|
|
68
70
|
if not hasattr(self, func):
|
|
69
71
|
if abort:
|
|
@@ -114,10 +116,14 @@ class Device(SysTree):
|
|
|
114
116
|
return self.sysfs.read_float(attr)
|
|
115
117
|
case "int":
|
|
116
118
|
return self.sysfs.read_int(attr)
|
|
119
|
+
case "hex":
|
|
120
|
+
return self.sysfs.read_hex(attr)
|
|
117
121
|
case _:
|
|
118
122
|
raise UnsupportedModeError(f"Mode {mode} is not supported")
|
|
119
123
|
|
|
120
|
-
def read_attr_or_default(
|
|
124
|
+
def read_attr_or_default(
|
|
125
|
+
self, attr: str, mode: str = "utf", strip: bool = True, default=None
|
|
126
|
+
):
|
|
121
127
|
try:
|
|
122
128
|
return self.read_attr(attr, mode, strip)
|
|
123
129
|
except UnsupportedModeError:
|
|
@@ -149,7 +155,11 @@ class Device(SysTree):
|
|
|
149
155
|
None:
|
|
150
156
|
If the sysfs device is not set or the attribute does not exist.
|
|
151
157
|
"""
|
|
152
|
-
if
|
|
158
|
+
if (
|
|
159
|
+
self.sysfs_device is not None
|
|
160
|
+
and len(attr) != 0
|
|
161
|
+
and attr in [x.name for x in self.sysfs_device.attributes]
|
|
162
|
+
):
|
|
153
163
|
return self.sysfs_device.read_attr_bytes(attr)
|
|
154
164
|
return None
|
|
155
165
|
|
|
@@ -222,7 +232,9 @@ class Device(SysTree):
|
|
|
222
232
|
|
|
223
233
|
chip_addr = self.device_args.get("addr")
|
|
224
234
|
if chip_addr is None:
|
|
225
|
-
raise ConfigError(
|
|
235
|
+
raise ConfigError(
|
|
236
|
+
f"{self.name}: Chip address not provided in board definition"
|
|
237
|
+
)
|
|
226
238
|
|
|
227
239
|
if not hasattr(self.parent, "sysfs_device") or self.parent.sysfs_device is None:
|
|
228
240
|
# our device is the top level device of the slot
|
|
@@ -230,12 +242,16 @@ class Device(SysTree):
|
|
|
230
242
|
slot_attributes = self.hw_module.slot.attributes
|
|
231
243
|
|
|
232
244
|
if slot_attributes is None:
|
|
233
|
-
raise ConfigError(
|
|
245
|
+
raise ConfigError(
|
|
246
|
+
f"{self.name}: Slot attributes not provided in system configuration"
|
|
247
|
+
)
|
|
234
248
|
|
|
235
249
|
if not self.hw_module.is_master:
|
|
236
250
|
# slot coding is only used for non-master devices
|
|
237
251
|
if not hasattr(slot_attributes, "slot_coding"):
|
|
238
|
-
raise ConfigError(
|
|
252
|
+
raise ConfigError(
|
|
253
|
+
f"{self.name}: Slot coding not provided in slot attributes"
|
|
254
|
+
)
|
|
239
255
|
|
|
240
256
|
slot_coding_mask = 0xFF
|
|
241
257
|
|
|
@@ -246,7 +262,9 @@ class Device(SysTree):
|
|
|
246
262
|
|
|
247
263
|
return chip_addr
|
|
248
264
|
|
|
249
|
-
def get_i2c_sysfs_device(
|
|
265
|
+
def get_i2c_sysfs_device(
|
|
266
|
+
self, addr: int, driver_required=True, find_driver: Callable | None = None
|
|
267
|
+
) -> SysfsDevice:
|
|
250
268
|
from ekfsm.core.components import HWModule
|
|
251
269
|
|
|
252
270
|
parent = self.parent
|
|
@@ -275,8 +293,12 @@ class Device(SysTree):
|
|
|
275
293
|
# regular I2C devices that follow the `${I2C_BUS}-${ADDR}` pattern. To address this issue, we
|
|
276
294
|
# initialize the ACPI _STR object for each PRP device with the necessary information, which is
|
|
277
295
|
# accessible in the `${DEVICE_SYSFS_PATH}/firmware_node/description` file.
|
|
278
|
-
if (entry / "firmware_node").exists() and (
|
|
279
|
-
|
|
296
|
+
if (entry / "firmware_node").exists() and (
|
|
297
|
+
entry / "firmware_node" / "description"
|
|
298
|
+
).exists():
|
|
299
|
+
description = (
|
|
300
|
+
(entry / "firmware_node/description").read_text().strip()
|
|
301
|
+
)
|
|
280
302
|
acpi_addr = int(description.split(" - ")[0], 16)
|
|
281
303
|
|
|
282
304
|
if acpi_addr == addr:
|
|
@@ -289,11 +311,16 @@ class Device(SysTree):
|
|
|
289
311
|
if acpi_addr == addr:
|
|
290
312
|
return SysfsDevice(entry, driver_required, find_driver)
|
|
291
313
|
|
|
292
|
-
raise FileNotFoundError(
|
|
314
|
+
raise FileNotFoundError(
|
|
315
|
+
f"Device with address 0x{addr:x} not found in {i2c_bus_path}"
|
|
316
|
+
)
|
|
293
317
|
|
|
294
318
|
@staticmethod
|
|
295
319
|
def __master_i2c_get_config(master: "HWModule") -> dict:
|
|
296
|
-
if
|
|
320
|
+
if (
|
|
321
|
+
master.config.get("bus_masters") is not None
|
|
322
|
+
and master.config["bus_masters"].get("i2c") is not None
|
|
323
|
+
):
|
|
297
324
|
return master.config["bus_masters"]["i2c"]
|
|
298
325
|
else:
|
|
299
326
|
raise ConfigError("Master definition incomplete")
|
|
@@ -310,7 +337,9 @@ class Device(SysTree):
|
|
|
310
337
|
else:
|
|
311
338
|
# another board is the master
|
|
312
339
|
if self.hw_module.slot.master is None:
|
|
313
|
-
raise ConfigError(
|
|
340
|
+
raise ConfigError(
|
|
341
|
+
f"{self.name}: Master board not found in slot attributes"
|
|
342
|
+
)
|
|
314
343
|
|
|
315
344
|
master = self.hw_module.slot.master
|
|
316
345
|
master_key = self.hw_module.slot.slot_type.name
|