Continuing the discussion from Controlling onboard LEDs on Rpi 4:
Read this thread and happy to hear that the dev team is working on solutions to better control the on-board LEDs. Yet, to elaborate a little more on our own project requirements and to give the devs another practical example, I would like to start this new thread.
The board on our hand is a ASUS Tinker Board. It has three LEDs on board - the RED, the GREEN and the YELLOW.
Our goal is to build a screen-less control unit for a vending machine. So these on-board LEDs are critical for quickly identifying issues on a field environment. Ideally, we would like the following design:
GREEN - SOLID_ON for power-on. BLINK for OS related, non-operational, non-critical activities/issues like disk writes and network drops - just as the current blink patterns when VPN goes off. Yet, these triggering signals has to be inverted in order to combine them with the solid power-on signal to actually create the blinks. And the blinks has to be muxed, too, so that multiple triggers can be gracefully blend into one single output. This design would help us to identify network issues, as well as to hint us with our best efforts to avoid a power unplugging during busy disk writes.
YELLOW - DEFAULT_OFF. SOLID_ON/BLINK for service related, operational triggers like GPIO activities, UART transmission, I2C transmission, SPI transmission, or even PWM controls. Surely, we can do this from user code. Yet, it’d be more elegant for the kernel to provide such facilities to offload our user space coding.
RED - DEFAULT_OFF. BLINK for thermal over heating, eFuse, etc., system-related faults or warnings. SOLID_ON for service related exceptions, like a door being blocked from closing or RFID reading errors. This latter one should be signaled from user code, of course. Still, a mux mechanism is needed for these signals to properly overlaying with each other. Also, the kernel should provide set-and-forget APIs for user code to register such triggers and patterns so that async code could be better devised.
RED AND YELLOW - INTERLEAVE_BLINK for kernel panic, such as accidentally removal of a SD card, so that we can safely cycle the power under such dead circumstances.
We have tried hard on Device Tree to achieve these desired features. Yet, from what we have tested, the current implementation seems to be incapable. Especially, the trigger-sources
and function
properties on the led
nodes seems to get completely ignored. The only well working property seems to be the linux,default-trigger
, and its few acceptable options are a mix of limited trigger sources and some ambiguous patterns:
# cat /sys/class/leds/led1-led/trigger
[none] rc-feedback kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock mmc0 mmc1 timer oneshot heartbeat backlight gpio cpu0 cpu1 cpu2 cpu3 default-on mmc2 rfkill0 rfkill1
_
While a large portion of these triggers are rarely used keyboard indicators, the "mmc0"
and "gpio"
are the sole two left for us to be interested in. Yet, as there’s currently no muxing, setting the "mmc0"
option will take precedence over default-state = "on"
, rendering the LED to become normal-off and showing SD card access only. We have no option but to dedicate the GREEN LED to power-on, and move the "mmc0"
trigger to the YELLOW one, dropping any service related activities and showing only abnormal states through user code on RED. Unfortunately, as we move the pointer in supervisor.conf
to the RED, without extra muxing code the same masking effect either mutes all our custom alarms, only showing the network status, or vice versa. Following is the snippet from the current dts file we’re using:
gpio-leds {
compatible = "gpio-leds";
red-led {
gpios = <0x2d 0x03 0x00>;
linux,default-trigger = "default-off";
};
grn-led {
gpios = <0xa8 0x18 0x00>;
linux,default-trigger = "default-on";
};
ylw-led {
gpios = <0xa8 0x19 0x00>;
linux,default-trigger = "mmc0";
};
};
Little to elaborate, we just renamed the LEDs for easy identification. However, we propose taking full advantage of the data tree semantics to achieve the desired results, as follows:
thermal-zones {
...
soc-thermal {
...
trips {
soc-crit: soc-crit {
...
#trigger-source-cells = <0x02>; // Setting parameter numbers to 2.
};
};
};
...
};
...
gpio-leds {
compatible = "gpio-leds";
red-led {
gpios = <0x2d 0x03 0x00>;
default-state = "on"; // Setting the default state;
// BLINK signals should automatically get inverted upon setting this to "on".
trigger-sources = <&soc-crit LED_SLOW_BLINK 0x01>, <&efuse@ffb40000 LED_FAST_BLINK 0x02>; // Phandle with two parameters:
// <&phandle PATTERN precedence>,
// same precedence number means
// a direct combination.
panic-indicator = "true"; // LEDs including this property should be signaled to INTERLEAVE_BLINK upon a kernel panic.
};
...
};
_
Well, this certainly means to modify the gpio-leds
driver. As we are busy implementing our own services, there’s no time for us to look into the kernel drivers and build our customized image. So, we’re going with the current settings, and in hope for an official release to provide such improvements.
I’ve given enough discussion on our real world example, I believe. We sincerely wish that the dev team can make more polish on the BalenaOS, to unleash the full power of SBCs!