RouterStation Pro firmy Ubiquiti jest świetną platformą dla osób lubiących grzebać zarówno w oprogramowaniu(firmware) oraz samej elektronice. Należę właśnie do takich osób, zawsze lubiłem majsterkować, tworzyć coś własnego
Dlatego też wyprzedałem inne bezużyteczne zabawki i zakupiłem RSPRO. Warto! Oprócz naprawdę potężnego procesora (jak na współczesne routery) i sporej pamięci typu NAND i RAM dostajemy kilka linii GPIO do własnego wykorzystania. W tym artykule właśnie dla GPIO poświecę najwięcej miejsca.
GPIO (ang. General Purpose Input/Ouptut) to fizycznie pin - „nóżka” procesora, która może działać jako wejście lub wyjście. W RouterStation Pro dostępne jest 7 linii GPIO do własnego wykorzystania.
Pora przejść do praktyki. Wykorzystamy kilka linii GPIO i podłączymy dwie diody LED i jeden przycisk. Pierwsza dioda LED to w zasadzie trzy, bo jest to RGB(Czerwona/Zielona/Niebieska). Jeżeli komuś szkoda trzech linii dla jednej diody można zastosować trzy rożne, nie ma problemu. Po prostu uwielbiam diody takiego tylu i taką zastosowałem. „Lampka” RGB jest ze wspólna anodą, o średnicy 5mm. Druga dioda jest koloru czerwonego o średnicy 3mm, w sam raz na „heartbeat” (o czym dalej). Przycisk jaki zastosowałem to normalnie otwarty, czyli daje przejście w obwodzie po jego wciśnięciu. Opisuje to ponieważ będzie to miało swoje odzwierciedlenie w kodzie jaki będziemy modyfikować.
Ważną sprawą w przypadku diod LED jest żeby nie podłączać ich bezpośrednio do pinów GPIO i GND/VCC. Należy zastosować rezystor ograniczający. Taki rezystor spełnia dwa zadania, ogranicza napięcie do potrzebnego dla diody oraz eliminuje zwarcie. Rezystor jest bardzo łatwo wyliczyć z prawa Ohma. Wystarczy odjąć napięcie zasilania od napięcia przewodzenia i podzielić przez prąd przewodzenia diody. Dla diody LED 3mm będzie to 3.3V-1.9V/0,02A. Z obliczeń wynika, że musimy zastosować co najmniej rezystor 70OM. Ciężko zdobyć taki rezystor w jednym elemencie, dlatego stosujemy 100OM. Jednak nie zalecałbym tego akurat w tym zastosowaniu, gdyż taka dioda będzie świecić ze swoją pełna mocą, co może w nocy fajnie oświetlać pokój
Proponuje te wartość 3-krotnie zwiększyć, rezystor na poziomie 200-300OM jest w sam raz. W przypadku diody RGB należy dobrać rezystory na każdą katodę(3). Ogólnie w przypadku diody RGB podłączenie będzie nieco inne, gdyż anodę(+) podłączamy do zasilania, a katody(-) do trzech oddzielnych GPIO. Podłączenie odwrotne z jednym sygnałem z GPIO załączało by trzy diody naraz, a tego nie chcemy. Zastosowanie RGB ze wspólna katodą odwróciło by to wszystko co wyżej napisałem.
W przypadku przycisku również należy zastosować rezystor, tutaj będzie zabezpieczał przez bezpośrednim zwarciem masy z GPIO.
Załóżmy, że mamy już wszystko polutowane, przejdźmy do sprawy programowej. Kod źródłowy na którym bazuje port RouterStation Pro jest na licencji GPL, tak więc zgodnie z jej treścią możemy go modyfikować. W naszym przypadku modyfikacjom ulegnie tylko jeden plik – mach-ubnt.c. Poniżej zamieszczam patch z modyfikacjami:
--- a/arch/mips/ar71xx/mach-ubnt.c 2010-04-03 08:51:26.000000000 +0200
+++ b/arch/mips/ar71xx/mach-ubnt.c 2010-11-28 17:50:31.477281669 +0100
@@ -22,6 +22,11 @@
#include "dev-usb.h"
#define UBNT_RS_GPIO_LED_RF 2
+#define UBNT_RS_GPIO_LED_C0 0
+#define UBNT_RS_GPIO_LED_C1 1
+#define UBNT_RS_GPIO_LED_C2 3
+#define UBNT_RS_GPIO_LED_HB 4
+#define UBNT_RS_GPIO_CB0 7
#define UBNT_RS_GPIO_SW4 8
#define UBNT_LS_SR71_GPIO_LED_D25 0
@@ -45,6 +50,22 @@
.name = "ubnt:green:rf",
.gpio = UBNT_RS_GPIO_LED_RF,
.active_low = 0,
+ }, {
+ .name = "ubnt:red:c0",
+ .gpio = UBNT_RS_GPIO_LED_C0,
+ .active_low = 1,
+ }, {
+ .name = "ubnt:green:c1",
+ .gpio = UBNT_RS_GPIO_LED_C1,
+ .active_low = 1,
+ }, {
+ .name = "ubnt:blue:c2",
+ .gpio = UBNT_RS_GPIO_LED_C2,
+ .active_low = 1,
+ }, {
+ .name = "ubnt:red:hb",
+ .gpio = UBNT_RS_GPIO_LED_HB,
+ .active_low = 0,
}
};
@@ -108,6 +129,13 @@
.threshold = 3,
.gpio = UBNT_RS_GPIO_SW4,
.active_low = 1,
+ }, {
+ .desc = "cb0",
+ .type = EV_KEY,
+ .code = BTN_1,
+ .threshold = 3,
+ .gpio = UBNT_RS_GPIO_CB0,
+ .active_low = 1,
}
};
Plik z patchem można pobrać stąd.
Wykorzystujemy cztery GPIO do podłączania diod LED. Pierwsze trzy(0-2) dla diody RGB, oraz 4 dla diody 3mm czerwonej (GPIO 2 pomijamy bo tam podpieta jest dioda RF). Na początku definiujemy nazwę GPIO oraz pin. Nazwa sprawa dowolna, pin już nie. Następnie w strukturze gpio_led ubnt_rs_leds_gpio[] dokładnie definiujemy jak nasze GPIO będzie widoczne w systemie. Nazewnictwo (.name) zgodnie z przyjętą konwencją platforma:kolor:przeznaczenie. Pozycja .active_low oznacza stan jaki ma panować na wyjściu w stanie spoczynku. W tym przypadku jest 1 ponieważ dioda LED będzie załączana stanem niskim na wyjściu. W przypadku diody 3mm jest już „normalnie”. W stanie spoczynku panuje 0 i załączamy 1, czyli 5V na GPIO.
W przypadku przycisku jest podobnie. Definicja nazwy, pinu GPIO i potem bardziej szczegółowy opis przycisku. Ważne tutaj jest poprawne wpisanie nazwy (.code), .desc, który jest aliasem(skrótem) do .code oraz .gpio. Możemy się posługiwać obiema nazwami w OpenWrt. U mnie jest to BTN_1 oraz cb0 od „custom button”. .active_low musi być 1 przy zastosowaniu przycisku zwiernego, przy rozwiernym dajemy 0 i podłączamy przycisk miedzy GPIO, a VCC.
Ostatecznie, mamy 4 diody nazwane: ubnt:red:c0, ubnt:green:c1, ubnt:blue:c2, ubnt:red:hb, oraz przycisk cb0. Tymi nazwami będziemy się posługiwać konfigurując odpowiednie sekcje w /etc/config/system
Pozostaje umieścić patch w target/linux/ar71xx/patches-2.6.3X/ pod nazwą 1000-custom-buttons-and-leds.patch i skompilować od nowa OpenWrt, wykonując make clean, gdyż kernel będzie paczowany.
Poniżej zamieszczam schemat ideowy. Przewody zaznaczone kolorem białym oznaczają masy, kolorem niebieskim sygnały z GPIO, kolor żółty to zworka przy GP7 wymuszająca stan wysoki. Konieczna jest do poprawności działania przycisku. Po poprawnym podłączeniu należy wgrać uprzednio skompilowany firmware.
Przydało by się sprawdzić czy dodane elementy działają. W przypadku przycisku tworzymy prosty skrypt w /etc/hotplug.d/button o nazwie button i zawartości:
#!/bin/sh logger $BUTTON logger $ACTION
Potem tylko
logread -f
I ciskamy przyciska
U mnie pokazuje się w logu:
Jan 1 23:56:58 OpenWrt user.notice root: BTN_1 Jan 1 23:56:58 OpenWrt user.notice root: pressed Jan 1 23:56:59 OpenWrt user.notice root: BTN_1 Jan 1 23:56:59 OpenWrt user.notice root: released
Działa!
Sprawdźmy „lampki”:
echo 1 > /sys/class/leds/ubnt:red:c0/brightness (zapala się czerwona dioda RGB) echo 0 > /sys/class/leds/ubnt:red:c0/brightness (gaśnie)
echo 1 > /sys/class/leds/ubnt:green:c1/brightness (zapala się zielona dioda RGB) echo 0 > /sys/class/leds/ubnt:green:c1/brightness (gaśnie)
echo 1 > /sys/class/leds/ubnt:blue:c2/brightness (zapala się niebieska dioda RGB) echo 0 > /sys/class/leds/ubnt:blue:c2/brightness (gaśnie)
echo 1 > /sys/class/leds/ubnt:red:hb/brightness (zapala się czerwona dioda 3mm) echo 0 > /sys/class/leds/ubnt:red:hb/brightness (gaśnie)
U mnie działają wszystkie :)
Należało by przyjąć jakieś funkcje dla nowo dodanych elementów. W moim przypadku dioda czerwona 3mm (ubnt:red:hb) będzie odzwierciedleniem obciążenia systemu. Przydzielę jej trigger heartbeat i będzie sobie spokojnie migać jak alarm w aucie :P Gdy router dostanie w kość to trochę ożywi się
Oto konfiguracja:
uci add system led uci set system.@led[-1].name=HB uci set system.@led[-1].trigger='heartbeat' uci set system.@led[-1].sysfs='ubnt:red:hb' uci commit system
Pod przycisk przypiszę ogólnie już oklepany pomysł - włączanie i wyłączanie wifi. Konfiguracja:
uci add system button uci set system.@button[-1].button=BTN_1 uci set system.@button[-1].action=released uci set system.@button[-1].handler="logger wifi on; uci set wireless.radio0.disabled=0;wifi" uci set system.@button[-1].min=1 uci set system.@button[-1].max=3 uci add system button uci set system.@button[-1].button=BTN_1 uci set system.@button[-1].action=released uci set system.@button[-1].handler="logger wifi off; uci set wireless.radio0.disabled=1;wifi" uci set system.@button[-1].min=3 uci set system.@button[-1].max=5 uci commit system
Przytrzymanie przycisku na 1-3sek włącza radio, a na 3-5sek wyłącza.
Pod diodę RGB koloru niebieskiego przypiszę aktywność wsadzonego urządzenia USB. Przykład pliku /etc/hotplug.d/usb/10-usb:
#!/bin/sh case "$ACTION" in add) echo 1 > /sys/class/leds/ubnt:blue:c2/brightness ;; remove) echo 0 > /sys/class/leds/ubnt:blue:c2/brightness ;; esac
Zaznaczę, że to tylko przykłady i docelowe funkcje należy sobie przydzielić wg. własnych potrzeb.
Takim oto sposobem wykorzystaliśmy klika linii GPIO. Chciałem w artykule przedstawić zastosowanie które będzie w sposób maksymalny wykorzystywało zintegrowanie z systemem OpenWrt. Chodzi mi tutaj o sposób konfiguracji w /etc/config/system.
Żeby w ogóle sterować GPIO nie trzeba modyfikować kodu, wystarczy tylko uaktywnić GPIO w /sys/class/gpio i dalej nim sterować. Jednak tutaj nie wykorzystalibyśmy zdarzeń jakie zachodzą w systemie (heardbeat, aktywność na interfejsie) w sposób tak łatwy jak to jest domyślnie.
Przytoczone zastosowanie to tylko przedbiegi przez poważnymi projektami. Można spróbować podłączyć inne elementy elektroniczne, jak przekaźniki i załączać nimi inne urządzenia. Możliwości jest wiele.
