Customizing the LEDs on the Netgate SG-3100
The SG-3100 pfSense appliance from Netgate has three RGB LEDs on the front. By default, the black diamond LED slowly "breathes" blue when everything is normal, and the green circle LED slowly "breathes" red when there is a software update. During boot, the circle LED quickly "breathes" blue, followed by the square, and finally the diamond. Since I'm always curious (and because the bright blue light was beginning to bother me), I went about figuring out how to individually control each LED (nine in total, for three full RGB LEDs). My starting point was a post by @stephenw10 on the Netgate forums.
Edit (27/09/2020): It turns out that the GPIO device might not always be
0, here's a way to get the GPIO device ID (credit: github.com/justdaniel-gh):
sysctl dev.gpio | grep .led. | cut -d . -f 3 | uniq
Edit (18/02/2020): This still works for the new pfSense Plus edition (21.02), although my GPIO ID changed from
2 after the upgrade.
The LED Driver
Here's the output of
dmesg that shows the LED driver being loaded:
---<<BOOT>>--- Copyright (c) 1992-2020 The FreeBSD Project. Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994 The Regents of the University of California. All rights reserved. FreeBSD is a registered trademark of The FreeBSD Foundation. FreeBSD 12.2-STABLE 38a4c12973d(plus-devel-12) pfSense-SG-3100 arm FreeBSD clang version 10.0.1 ([email protected]:llvm/llvm-project.git llvmorg-10.0.1-0-gef32c611aa2) CPU: ARM Cortex-A9 r4p1 (ECO: 0x00000000) ... ofwbus0: <Open Firmware Device Tree> simplebus0: <Flattened device tree simple bus> on ofwbus0 simplebus1: <Flattened device tree simple bus> on simplebus0 ... twsi0: <Marvell Integrated I2C Bus Controller> mem 0x11000-0x1101f irq 5 on simplebus1 iicbus0: <OFW I2C bus> on twsi0 iic0: <I2C generic I/O> on iicbus0 gpio2: <NXP PCA9552 LED driver> at addr 0xc0 on iicbus0 device_attach: gpio2 attach returned 6 gpio2: <ISSI IS31FL3199 9 channel light effect LED driver> at addr 0xce on iicbus0 gpiobus2: <OFW GPIO bus> on gpio2 gpioc2: <GPIO controller> on gpio2 ...
Customizing the Status LEDs
A LED group has a red, green, and blue led in it, making it a single RGB unit. There are three LED groups, the green circle (), blue square (), and black diamond (). Each LED group is addressed as an
led, according to the following table:
Each LED colour is addressed as a
pin, according to the following table:
RGB Control Mode
The LED controller has two RGB modes, PWM and One Shot Programming. PWM mode means the LEDs are only controlled by the duty cycle (brightness). One Shot Programming mode enables the timing characteristics (rising, holding, falling, & off time) of the controller IC, which allows creating patterns.
To enable PWM mode (disabling One Shot mode):
To enable One Shot mode (disabling PWM mode):
There is a fourth setting for each LED group, called Double Time. Double Time is where
T3 is calculated by doubling the value of
T3 = 2 * (T1)
Enable Double Time:
Disable Double Time:
The brightness for each individual LED colour has 256 levels, where
0 is off and the remaining 255 are brightness levels. The brightness is set using the
gpioctl command to configure the PWM duty cycle.
gpioctl -f /dev/gpioc<gpio> <pin> duty 0
gpioctl -f /dev/gpioc<gpio> <pin> duty 255
If you supply a value above 255, the value is interpreted as starting from 0, with the greatest factor of 256 subtracted. E.g.
256 is the same as
256 - 256 = 0, which would be off.
The three groups of three LEDs (nine total) are controlled by the IS31FL3199 integrated circuit from Integrated Silicon Solution, Inc.
The most useful piece of information from the IS31FL3199 LED controller datasheet is this breathing timing graph (figure 7):
|Register||Timing Stage||Maximum value||Notes|
||value will be equal to
In case you're interested, there is more detailed timing info in tables 11, 12, and 13.
Changing the timings for each of the breathing stages is done using the
To set the
T0 (off time) timing for a single LED:
To set the
T4 (off time) timing for a single LED:
To set the
T2 (hold time) timing for an LED group:
To set the
T1 (rising time) and
T3 (falling time) timing for an LED group:
These commands will configure the first LED (green circle) to breathe red, green, and blue sequentially. This example assumes the GPIO device ID is
# Turn up the brightness gpioctl -f /dev/gpioc0 6 duty 128 gpioctl -f /dev/gpioc0 7 duty 128 gpioctl -f /dev/gpioc0 8 duty 128 # Green Circle LED sysctl dev.gpio.0.led.2.T2=1040 sysctl dev.gpio.0.led.2.T1-T3=520 # Red colour sysctl dev.gpio.0.pin.6.T0=0 sysctl dev.gpio.0.pin.6.T4=4160 # Green colour sysctl dev.gpio.0.pin.7.T0=2080 sysctl dev.gpio.0.pin.7.T4=4160 # Blue colour sysctl dev.gpio.0.pin.8.T0=4160 sysctl dev.gpio.0.pin.8.T4=4160
The range of settings available for the three front status LEDs on the Netgate SG-3100 creates a lot of posibilities for extending their use. The center (blue square) LED isn't currently used after the boot process, and could be configured to indicate the WAN status, etc. Personally, I only need a dim blue LED for now, just to indicate that the appliance is powered on. To achieve this, I installed the
shellcmd package, and created a command that will dim the LED near the end of the boot process.
sysctl dev.gpio.0.led.0.pwm=1; gpioctl 2 duty 2