GPIO LED control

using 2.5.3 sdk. Our board 7688/silex board has LEDs configured w/ red using gpio44, blue gpio18, green gpio19. Main question: How to capture a halow connection/disconnection to control the LEDs? We want green on/red off for halow connected, green off/red on for halow not connected.

I can use this in dts and I can see green when halow connects:

            led_green: green { 
                   label = "green:sys"; 
                   gpios = <&gpio 19 GPIO_ACTIVE_HIGH>; 
                   linux,default-trigger = "phy3assoc";
           }; 

However…this works only if the halow radio is using phy3. This doesn’t work because if we load the image, the green triggers have phy1 for phy1radio, phy1assoc, phy1rx, phy1tx, but right after running the wizard, the green triggers change from phy1 to phy3. So, yes, the green led will go on when halow connects as it’s associated with phy3 after running wizard the first time. BUT…if we software reboot, then it boots as phy2 and, thus, even though luci shows connected halow, the green won’t go on since its trigger is phy3. (this is the list of triggers after reboot: [none] switch0 timer heartbeat default-on netdev phy0rx phy0tx phy0assoc phy0radio phy0tpt usbport mmc0 phy2rx phy2tx phy2assoc phy2radio).

So, since this method seems unreliable, unless there’s a way to control that, is there any other way to know when halow connects/disconnects so we can control the led ourselves through led on/off of any colors we want? Some file that handles events? A script that runs based on an event?

From the 2.5.3 sdk I’ve been trying to figure out how morse does the led for ekh03-05 kit for changing the various colors of the led (including yellow, the combo of red & green). How are events captured? How do you control it? I only saw green led defined in the ekh0304 dts file and haven’t been able to find where other led controls are for your kit.

Hi Don,

As of the 2.5.3 Morse Micro SDK release, the EKH03 used the simple LED aliases as defined by OpenWrts /etc/diag.sh script. There are 4 LED aliases defined by default in OpenWrt: boot, failsafe, upgrade, and running. You’ll see these aliases mapped in devicetree as

aliases {
	led-boot = &led_boot;
	led-failsafe = &led_failsafe;
	led-dpp = &led_failsafe;
	led-running = &led_boot;
	led-upgrade = &led_upgrade;
	label-mac-device = &wmac;
};

A very brief summary of the default states used by OpenWrt:

  • The boot state is set in /lib/preinit/10_indicate_preinit and configures led-boot to flash.
  • The failsafe state is set in /lib/preinit/10_indicate_failsafe and configures led-failsafe to flash.
  • The upgrade state is set in /lib/upgrade/common.sh and configures led-upgrade to flash
  • The done state is set in /etc/init.d/done (which is the last service started by procd), and configures led-running to the on state.

I would recommend reading through /etc/diag.sh and /lib/functions/leds.sh for further info on those default LED states.

There is a non-standard OpenWrt LED alias defined in that list, led-dpp, which was added by Morse Micro. You’ll see this LED is used in a script wpa_s1g_dpp_action.sh deployed by the netifd-morse package. Through a few layers of application, this script is called in response to DPP events seen on the wpa_supplicant and hostapd control sockets. I don’t want to spend too much time in the details of this LED though, as it is a little application specific and we are changing how this LED is driven in later versions.


To finally answer your question as specific to your application. OpenWrt has a number of ways to configure LEDs of different functions. Normally, when phy interface numbers remain static, routers will set the intended functionality through UCI via a special board.d script which builds device configuration at first boot. See for example, target/linux/ramips/mt76x8/base-files/etc/board.d/01_leds which defines some netdev triggered LEDs.

However, given that the Morse Micro driver module is sometimes reinserted - the phy number does change. These reinsertions are sometimes necessary while we have to self-manage the 802.11ah regulatory domains.
To handle this, you may want to consider leveraging a hotplug script, instead of UCI, to set this LED state when the new phy is created. Unfortunately, ieee80211 hotplug events do not appear to be documented in the above link, but most ramips targets deploy one you could use as a starting reference - see target/linux/ramips/mt76x8/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac.

With an ieee80211 hotplug script reacting to $ACTION == "add", you could then simply extract the phy number as done in 10_fix_wifi_mac, and set your led triggers directly using Linux sysfs. You may want to also look at how /lib/functions/leds.sh configures LEDs using sysfs.

I realise that’s a very long response to your questions, but I hope it has helped! If you need more clarification, or assistance with the hotplug script and device tree configuration feel free to ask!

Hi, Arien. I appreciate the response and details. You mentioned it being a long response – long is GOOD. I appreciate every detail and this was helpful. And it was a prompt response, too, which I also appreciate. Just being frank here: it’s been a bit frustrating with the amount of time it takes to get support response from morse support staff. While there have been a few very useful tidbits, it’s (understand from my perspective) been very frustrating when there are no responses. Not dumping on you, just mentioning, and back to appreciating your timely response.

With this info, I was able to get an outside tip on how to identify which phyn is used based on the driver reinsertion (adding code in /lib/netifd/wireless/morse.sh, which it seems that script file is gone through when there’s a halow connect or disconnect. That new code determined the other phyn besides 0 and did: echo “$led_trig” > /sys/class/leds/red:sys/trigger) and between that and defining the red led in the dts to be inverted from the green led, I can use the same phynassoc trigger on both leds for the client. Thus, the green led lights when halow connected, red when halow disconnected. This is a single led controlled by rgb on 3 gpio pins, so I need the proper coordination.

Related to this, and continuing this topic, the green led on the client device turns on when halow connects and I can see the events in the debug log using teraterm showing this process until it shows wlan0 associated, but nothing like that happens on the ap. I’d like the ap to also have its led turn green when any clients are connected. That can be 1…n, is that right? The log in the debug output off the uart is the same log you see from “dmesg log”. On the AP, no events happen in this log during halow connect or disconnect. However, use “logread” and you see these other messages that show AP-STA connected or disconnected. I don’t know where those are coming from.

The question is, on the AP, how can I know that there was a client connect or disconnect and how would I know how many clients are connected (if that’s applicable)? I’d like to be able to control the led from this.

Any idea?

Don

Happy to help Don!

/lib/netifd/wireless/morse.sh, which it seems that script file is gone through when there’s a halow connect or disconnect.

If this script suits your needs, then modifying the script there should be sufficient! I would clarify by saying that this script is called by the netifd service daemon on OpenWrt which is typically re-triggered when the configuration changes.

I have a personal preference for hotplug.d scripts, as they can be then treated as separate packages - which may help with feature management. So would recommend you have a look at that avenue too! The events in these hotplug scripts won’t necessarily correlate with the same events triggering functions in morse.sh. So can appreciate if they don’t suit your needs.

use “logread” and you see these other messages that show AP-STA connected or disconnected. I don’t know where those are coming from.

These events will be coming from hostapd_s1g which is responsible for handling the HaLow AP functionality on the interface.

I’d like the ap to also have its led turn green when any clients are connected. That can be 1…n, is that right?

There are going to be a few different ways to implement this, and I might refrain from pointing out a specific approach as “ideal”, as they all will have their own tradeoffs.

There’s also an extra complexity here in that existing associated clients may leave the network without cleanly disassociating from the AP. So while you should be able to react quite quickly to association events, in some cases there may not be a clear disassociation event - and in some cases it may be simpler to periodically poll the list of associated stations.

Lots of words there without clear direction! For detecting association, the three options which come to mind immediately for me are:

  • write an application which listens to events on the hostapd control socket, then probably wrap this in a procd service so it runs on boot. You will need to check wpa_supplicant / hostapd: hostapd control interface for information on the events advertised on the control socket. I’m not aware of any examples internally leveraging this directly. I will look!
  • You might be able to leverage ubus to capture some of these events as well. Unfortunately, because we’ve had to provide a modified hostapd for HaLow support, our hostapd_s1g is missing some of the helpful ubus hooks - ie those described on this page. So you may be limited to the iwinfo object.
  • Poll a utility like iwinfo wlan0 assoclist or it’s ubus equivalent to check associated stations. This is probably the wrong approach for detecting association, but it may be the most reliable for keeping track of a total list of associated stations, especially if they leave without sending an appropriate frame to disassociate - polling will capture those stations which time out. The iwinfo ubus endpoint does work fine for the HaLow interfaces.

I’ll see if I can work up an example for a couple of the above for you. Not sure I’ll be able to provide an example quickly though. Hopefully these pointers give a good place to start!

Thanks, Arien. Again, appreciate your details and responsiveness. This gives me some things to chew on. As you know, resources are somewhat limited regarding openwrt and especially when incorporating new tech like halow. Thus, it’s important to ask y’all for details to help understand.

And, yes, as you get some moments, examples are always excellent and sometimes vital. Sometimes you may understand what the problem is and know what you need to do but not know “how” to do it.

Regards,

Don

Arien, in a very related but slightly different issue on this topic we’re discussing, going to your first reply below for the morse.sh script, here’s something that’s happening when I turn the halow radio off then back on. In the morse.sh script, it’s able to set the led triggers based on the current phy[n]assoc when the halow radio comes up, authenticates and associates. Our led goes green when that assoc happens, red when it goes away (the red is active low, green active high so on the same trigger, they go opposite).

Here’s the problem I found. Refer to the attached pic then continue after viewing that.

Then, click the enable button on that 2nd line to start the radio back up again. Debug log shows things starting back up, authenticating and associating. The led turns green then a few seconds later, the associated stations in luci shows the ap information.

The bad: usually the led stays green, but sometimes, after 3 seconds, the led turns red, but luci still shows the associated station.

I found something in the log using ‘logread’ (which gives more info than the dmesg log which is simply the interactive output to the uart for teraterm). Right after the “wlan0: link becomes ready” line, in the following log items, whenever the line that looks like “Thu Nov 14 01:29:20 2024 user.notice root: Prplmesh is disabled” is in the log at that spot below, the led goes from green to red 3 seconds after it turns green. Makes total sense when you look at the timestamps of the log items. When that line isn’t there, the led stays green.

The log:

(As reference, after this line happens, green led immediately goes on)

Thu Nov 14 01:29:17 2024 kern.info kernel: [10976.730262] IPv6: ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready

(Then, each of these next entries are in all logs, except the prplmesh disabled – that’s only in the one where the led turned red. There’s some delay due to that because in the logs that green stayed on, the timestamp for all below are on the same second. Note how this happened 3 seconds after the led turned green, exactly what I counted when the led went re)

Thu Nov 14 01:29:17 2024 daemon.notice netifd: ahwlan (20405): udhcpc: started, v1.36.1
Thu Nov 14 01:29:17 2024 daemon.notice netifd: ahwlan (20405): udhcpc: broadcasting discover
Thu Nov 14 01:29:20 2024 user.notice root: Prplmesh is disabled
Thu Nov 14 01:29:20 2024 daemon.notice netifd: ahwlan (20405): udhcpc: broadcasting discover
Thu Nov 14 01:29:20 2024 daemon.notice netifd: ahwlan (20405): udhcpc: broadcasting select for 192.168.1.194, server 192.168.1.1
Thu Nov 14 01:29:20 2024 daemon.notice netifd: ahwlan (20405): udhcpc: lease of 192.168.1.194 obtained from 192.168.1.1, lease time 43200
Thu Nov 14 01:29:20 2024 daemon.notice netifd: Interface 'ahwlan' is now up

MORE INFO:

When I do “uci show”, it includes this in the output:

prplmesh.config.enable='0'

Was curious because when I did a grep for “Prplmesh is disabled”, the file ./feeds/prpl/prplmesh/files/etc/init.d/prplmesh came up and has the following routine:

start_service() {
    if [ "$(uci get prplmesh.config.enable 2>/dev/null)" = "1" ]; then
        start_agent_monitor
        procd_open_instance
        procd_set_param command /opt/prplmesh/scripts/prplmesh.init start
        procd_set_param stdout 1
        procd_set_param stderr 1
        procd_close_instance
    else
        logger "Prplmesh is disabled"
    fi
}

So, whatever is calling this start_service is then displaying that message. And it only calls this for whatever reason and because of that, turns the led red from green. And, both green and red are triggered by the phy[n]assoc it’s set to, as it shows when it just happened again:

root@ep-hilink-d94cda:/# cat /sys/devices/platform/leds/leds/green:sys/trigger
none switch0 timer heartbeat default-on netdev phy0rx phy0tx phy0assoc phy0radio phy0tpt usbport mmc0 phy32rx phy32tx [phy32assoc] phy32radio
root@ep-hilink-d94cda:/# cat /sys/devices/platform/leds/leds/red:sys/trigger
none switch0 timer heartbeat default-on netdev phy0rx phy0tx phy0assoc phy0radio phy0tpt usbport mmc0 phy32rx phy32tx [phy32assoc] phy32radio

I couldn’t find where start_service was called when I did a grep on the project.

So, what is it doing that makes the led go red but still shows in luci that halow is connected with the entry in the associated stations list?

Does all that make sense?

Don

(attachments)

Arien, I just sent a reply to below with some detailed specifics and your system bounced it back as being objectionable. There was nothing in there objectionable, abusive, or related. I’ll try the short version; if you want more detail, let me know how to get it to you.

It’s about an issue with the led going from green to red in 3 secs after I re-enable the halow radio after having disabled it. It doesn’t happen every time, though. Most of the time, the led goes and stays green right after we connect halow. Our led goes green when halow is associated, red when halow drops out. But, there’s a line in the log that only appears when something turns the led red after it went green for 3 secs: “Thu Nov 14 06:11:55 2024 user.notice root: Prplmesh is disabled”. It’s not like the halow connection dropped, as luci still shows it connected to the ap.

If you need more details, I can provide but that’s the short version. Just tell me how to provide so my note doesn’t get rejected by your system. But that line in the log is the one thing that’s consistent as it’s only there whenever it turns the led red after 3 secs.

Regards,

Don

Don-
We’re still tuning the content filters around here. I’ve approved that post.
-Zandr

Hi Don,

I took the liberty of wrapping some bits of your reply in code blocks.

Answering some questions which I’ve inferred from your post; feel free to clarify if I’ve misunderstood anything you’ve asked.

What is calling start_service?

start_service is being called by procd which is OpenWrt’s service management daemon. Similar to systemd on some Linux desktop distributions. procd will trigger a service restart for many reasons:

  • A script has called service prplmesh start or service prplmesh restart
  • The service has a dependency on another service, and is re-triggering as a result of another service.
  • The service has a dependency on a configuration file which has changed eg /etc/config/wireless

In particular, for prplmesh, the following line in the service script tells procd it should trigger a reload on change to specific configuration files.

procd_add_reload_trigger "prplmesh" "network" "wireless"

See this link and this link for more about procd.

what is it doing that makes the led go red but still shows in luci that halow is connected with the entry in the associated stations list?

From the logs shown, I think we can safely say the device is associated. It has a DHCP lease so there is network activity. I’m generally trustworthy of Linux sysfs functionality - like the phyNassoc LED trigger, as it is relatively simple and hooked directly into mac80211. So won’t look for bugs in that area, yet.

I would take the prplmesh line in logread as a hint that procd has reloaded a number of services. If this line is not showing in other logs, then there’s possibly more services reloading than expected.

Early versions of our morse.sh script did aggressively reinsert the driver which would trigger a phy number change. I’m skeptical that this is actually the problem, as I would not expect the LED trigger file to show phy number selected if that phy did not exist.
Can you verify the phy number of the HaLow interface matches the phy specified in the trigger file?

Can share exactly where in the morse.sh file you added the lines to set the trigger?

Good morning, Arien. Good info, thanks.

As I was preparing to answer your questions this morning, I was double checking some stuff. That code you asked about that was added morse.sh? Well, I put it in morse.sh, but I realized I had put it in /lib/wifi/morse.sh and meant to put it in /lib/netifd/wireless/morse.sh. It’s actually at the end of the file. So, I moved it to that one and thought I’d try disabling/enabling the morse radio again as I described. For an hour I’ve been disabling/enabling the halow radio, it’s up to phy37assoc and the green led has acted normally, meaning it came on when associated and didn’t turn red 3 secs after coming on. Plus, interestingly, that line “user.notice root: Prplmesh is disabled” is even in the log!

Is this all because /lib/wifi/morse.sh is launched before /lib/netifd/wireless/morse.sh and there’s something in the latter that’s run such that the trigger has to be set after that morse.sh runs?

Here’s the code I added at the end of /lib/netifd/wireless/morse.sh after the last line “add_driver morse”:

for item in `cat /sys/class/leds/green:sys/trigger`
do
    if [[ $item == "*assoc*" ]]; then
        if [[ $item != "phy0assoc*" ]]; then
            led_trig=$item
        fi
    fi
done

led_trig=`echo $led_trig | sed -e 's/\[//' | sed -e 's/\]//'`
echo "$led_trig" > /sys/class/leds/green:sys/trigger
echo "$led_trig" > /sys/class/leds/red:sys/trigger

(note: since red is active low, green active high, they get the same trigger)

So, there’s a saying “confession is good for the soul”. So, confession: I had put the code in the wrong file and if I hadn’t, I wouldn’t have seen that issue. There’s an end to that phrase few people use…”confession is good for the soul, but bad for the reputation”. At least this situation with the led appears to be working now. I figured an hour was a good amount of time to test since the bad condition would often appear about every few minutes of trying the dsbl/enbl cycle.

Thanks so much for your attention to this and the help you’ve been.

Finally: You asked: “Can you verify the phy number of the HaLow interface matches the phy specified in the trigger file?” I can get the phy trigger number from the list of “cat /sys/class/leds/green:sys/trigger”, but where do I find the phy number for the halow i/f?

Regards,

Don

Hi Don,

Glad you’ve resolved it!

but where do I find the phy number for the halow i/f?

There are many ways to find this. A simple one I would use for checking is
ls /sys/class/morse/morse_io/device/ieee80211

Is this all because /lib/wifi/morse.sh is launched before /lib/netifd/wireless/morse.sh

On insertion of a wireless driver module, and subsequent creation of the phy device, a hotplug script /etc/hotplug.d/ieee80211/10-wifi-detect executes. This hotplug scripts calls /sbin/wifi with the intention of adding configuration entries to /etc/config/wireless. It should be noted, however, that any time /sbin/wifi is executed, it “includes” every script in /lib/wifi/. This inclusion effectively executes every script in /lib/wifi/. Which will execute the lines you added.

When your addition is added to /lib/netifd/wireless/morse.sh then the LED configuration will be executed at anytime the netifd binary executes that handler (see this link for the line where netifd starts adding handlers to it’s internal registry). This will happen any time the network service is restarted, netifd detects a change to configuration, and possibly more.

Without further debugging, it’s still a little difficult to say conclusively why your LED configuration didn’t work correctly when in /lib/wifi/morse.sh. If I find the time to do further debug I definitely will.


If possible, I would recommend exploring a separate hotplug script so that you avoid the complexities of netifd, and maintain your changes separately from any updates we make to the netifd package.

I haven’t tested this, but you could add a new script to /etc/hotplug.d/ieee80211/ containing the following

#!/bin/sh

[ "${ACTION}" = "add" ] && {
	basename "$(readlink -f "/sys/${DEVPATH}/device/driver")" | grep '^morse_' || return;

	phy=${DEVPATH##*/}
	[ -n $phy ] || exit 0

	echo "${phy}assoc" > /sys/class/leds/green:sys/trigger
	echo "${phy}assoc" > /sys/class/leds/red:sys/trigger

}

This script will trigger whenever mac80211 registers a new phy. It will first check that phy is using a Morse Micro driver, then extract the phy name (eg, phy3), and then force your LEDs to the phyNassoc trigger.
If you’re feeling particularly fancy, you could leverage the functions in /lib/functions/leds.sh to get the leds by their device tree name.

Your note from reply 4 on 11/13 above was VERY helpful. The 3rd option “iwinfo wlan0 assoclist” got me a list of clients on the AP. Using that in a script, I used cron to launch a script every minute to check the output of that command. That output helps me know to turn my LED if clients are attached.

I then turned off a client and after a while, it eventually disappeared from the list. I disabled another client halow radio and it pretty much immediately disappeared from the list.

Questions:

  1. In the script, is there a command I can use that will give me the halow mac? (also, the device or wifi mac). Since the script is going to be part of the image regardless of it being an AP or client, that way I can filter. If the mac in the list is the same as the device halow mac, I’ll know I’m on a client and won’t mess with the LED, but if not it’s an AP and I should control the LED. Or, is there a better way to know and what other ways can you know if that device is an AP or client?

  2. What is the timeout when a client disappears without a proper disconnect before it disappears from that assoclist?

  3. is there a way to know on the AP when it gets a halow connection or disconnect (i.e. “daemon.notice hostapd_s1g: wlan0: AP-STA-CONNECTED ”, “daemon.notice hostapd_s1g: wlan0: AP-STA-DISCONNECTED ”)? I thought it would be preferrable to run the script at that time to have immediate reaction to the LED when the first client connects or the last client disconnects.

In the script, is there a command I can use that will give me the halow mac?

Do you mean the HaLow MAC of the device you intend to run the command on?
If you don’t want to parse the output of ifconfig or ip addr show, then perhaps using sysfs is sensible? Something like cat /sys/class/net/wlan0/address. This last command will return only the configured hardware address.


What is the timeout when a client disappears without a proper disconnect before it disappears from that assoclist?

This is actually a configurable parameter of hostapd! See these options available in uci [OpenWrt Wiki] Wi-Fi /etc/config/wireless
By default the max station inactivity is configured to be 5 minutes. A station may leave immediately if it sends a deauthentication frame. This will likely occur if the wpa_supplicant process is terminated cleanly, which rarely happens in reality. Typically a device goes out of range, or otherwise has its power pulled.


is there a way to know on the AP when it gets a halow connection or disconnec

There are a few ways to achieve this. I think the easiest approach is to use hostap_cli_s1g with an action script in daemon mode running in the background. For example, you could create a script named station_connected containing

#!/bin/sh

[ "$2" == "AP-STA-CONNECTED" ] && {
	echo "$@"
}

[ "$2" == "AP-STA-DISCONNECTED" ] && {
	echo "$@"
}
exit 0

and hook it into hostapd with
hostapd_cli_s1g -i wlan0 -a station_connected -B

When a station connects, the action script will run. If the event fired by hostapd is AP-STA-CONNECTED or AP-STA-DISCONNECTED this script will simply print the arguments of the event fired.


Alternatively, you could write a C application which uses the hostapd control interface to receive these events. We have an example application handling DPP push button events for wpa_supplicant available here. You’ll need to point this to the hostapd control interface, that is #define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd_s1g", and instead of listening for DPPPB events. You’ll probably want to receive AP_STA_CONNECTED and AP_STA_DISCONNECTED events. The full list of events for hostapd can be found here.

Hostapd documentation for the control interface can be found here. It is unfortunately, a bit light on explaining the details.

Hi, Arien. I tried the script and hostapd_cli_s1g below but didn’t see any effect. I disabled then reenabled the radio on the client to disconnect/reconnect through luci network/wireless.

I put that sample you showed into a file /lib/functions/clientconnected.sh, then ran “hostapd_cli_s1g -i wlan0 -a /lib/functions/clientconnected.sh -B” from the command line. I even added an echo, as below. I also tried renaming without the “.sh”, too. Am I doing something wrong?

#!/bin/sh

[ “$2” == “AP-STA-CONNECTED” ] && {

echo “$@”

echo “Client connected” > /dev/console

}

[ “$2” == “AP-STA-DISCONNECTED” ] && {

echo “$@”

echo “Client disconnected” > /dev/console

}

exit 0