
Witajcie moi drodzy
Przedstawię tutaj mojego shielda (nakładkę) na Arduino UNO opartego o układ ENC424j600. Shield ten pozwala podłączyć Arduino do internetu bez żadnego lutowania, a nawet bez użycia kabelków i płytek stykowych. W temacie dam jedenaście pełnych przykładów jego użycia z moimi komentarzami, dotyczyć one będą tematów takich jak UDP, TCP, NTP, DNS, DHCP i HTTP.
Wstęp
Jakiś czas temu opublikowałem na DIY projekt bazujący na ENC424j600 w temacie o nazwie Moduł łączności Ethernet ENC424J600 (czyli taki lepszy ENC28J60), tutaj:
https://www.elektroda.pl/rtvforum/topic3636658.html
Tak się złożyło, że po wykonaniu tamtego projektu zostało mi parę części, więc uznałem, że mogę je jeszcze jakoś lepiej wykorzystać, by nie kurzyły się w szufladzie.
Zobaczyłem też, że choć jest wiele shieldów łączności Ethernet dla Arduino, to shielda opartego ENC424J600 chyba nie ma - stąd wziął się pomysł.
Zasadniczo do tego projektu musiałem zaprojektować i zamówić tylko PCB - resztę już miałem na stanie.
Spis treści przykładów
W tym temacie zawarłem następujące przykłady użycia Arduino z ENC424 (a nawet niekoniecznie - te same metody można zastosować dla innych układów/modułów sieciowych):
- Przykład ENC424J600 na Arduino nr 1 - przypisujemy IP, pingowanie
- Przykład ENC424J600 na Arduino nr 2 - serwer TCP echo
- Przykład ENC424J600 na Arduino nr 3 - prosty klient DNS
- Przykład ENC424J600 na Arduino nr 4 - DHCP czyli automatyczne przypisywania konfiguracji IP dla Arduino
- Przykład ENC424J600 na Arduino nr 5 - DHCP + DNS
- Przykład ENC424J600 na Arduino nr 6 - klient UDP usługi NTP
- Przykład ENC424J600 na Arduino nr 7 - serwer TCP kalkulator
- Przykład ENC424J600 na Arduino nr 8 - serwer HTTP czyli nasza strona WWW
- Przykład ENC424J600 na Arduino nr 9 - klient HTTP (wysyłamy zapytanie GET)
- Przykład ENC424J600 na Arduino nr 10 - klient HTTP i argumenty zapytania GET
- Przykład ENC424J600 na Arduino nr 11 - klient HTTP - zapytanie GET reverse geocoding
Pełny kod Arduino każdego przykładu jest w treści tematu, nie trzeba nic pobierać.
Krótki słowniczek
W temacie używam dość dużo pojęć z którymi niektórzy mogą nie być zapoznani, dlatego umieszczam tutaj krótki słowniczek skrótów i wyjaśnień co jest czym. Wyjaśnienia poniżej oczywiście są bardzo uproszczone, nic nie zastąpi lektury dobrej książki.
UDP - User Datagram Protocol - bezpołączeniowy protokół internetowy, szybki lecz nie oferujący mechanizmów kontroli transmisji, może gubić pakiety, itd.
TCP - Transmission Control Protocol - połączeniowy protokół internetowy, wymaga nawiązania połączenia, zapewnia dostarczenie danych do celu, nieco wolniejszy.
DNS - Domain Name System - system nazw domenowych, w dużym skrócie zamienia nazwe hostu np. 'elektroda.pl' na jego adres IP np. 104.109.65.140
DHCP - Dynamic Host Configuration Protocol - protokół dynamicznego konfigurowania hostów, z reguły chodzi na routerze, automatycznie przypisuje hostom adresy IP ( z reguły zmienne), IP bramy sieciowej, maskę, itp. Przeciwieństwo konfigurowania IP 'na sztywno'.
NTP - Network Time Protocol - protokół sieciowy synchronizacji czasu. Opiera się na UDP, pozwala na synchronizację czasu pomiędzy komputerami. Można z niego pomocą pobrać aktualny czas z serwera.
HTTP - Hypertext Transfer Protocol - protokół przesyłania dokumentów sieci WWW. Opiera sie na TCP, jest tekstowy. To poprzez ten protokół działają strony internetowe
HTML - HyperText Markup Language - język znaczników do tworzenia dokumentów stron WWW. Pozwala formułować akapity, linki, nagłówki, listy, ustawiać czcionki, i znacznie, znacznie więcej.
W celu dokładniejszego poznania opisanych tu pojęć odsyłam do lepszych źródeł, np. nawet do wikipedii.
Projekt shielda
Schemat i PCB wykonałem w darmowej wersji programu Eagle. Punktem początkowym był design Arduino UNO (też w Eagle, na szczęście) i design mojej poprzedniej płytki pod ENC424:

Większość połączeń musiałem jednak poprowadzić od nowa:

ENC424J600 podłączyłem do pinów SPI od Arduino UNO, czyli:
- pin 11 - MOSI
- pin 12 - MISO
- pin 13 - SCK
- pin 10 - SS
Jednakże na płytce przed tymi pinami dałem zworki, na wypadek gdyby coś poszło nie tak.
Samo podłączenie Ethernetu do ENC424J600 jest zrealizowane zgodnie z notą katalogową:

Warto tu jednak zaznaczyć, że w projekcie użyłem tzw. złącza 'magjack', które ma w sobie już wszystko to co zaznaczyłem czerwoną ramką (czyli transformatorki, rezystory 75 omów, itp). Konkretnie to użyłem JXD0-0006NL.

Schemat wewnętrzny złącza pokazanego wyżej:

Nota katalogowa JXD0-0006NL:
ENC424J600 zasilany jest z 3.3V (5V go uszkodzi), więc na płytkę dałem też LDO 3.3V MIC2940A-3.3WU w obudowie TO-263:


Nota katalogowa MIC2940A:
Ten regulator napięcia na płytce może być zasilany z 5V z Arduino, albo bezpośrednio z jego VIN (MIC działa z VIN aż do +26V). Może być też całkiem pominięty (ale odradzam, bo to niepotrzebnie by obciążało 3.3V z Arduino).
Do SPI nie musiałem konwertować poziomów logicznych, gdyż piny ENC424 są '5V-tolerant':

Dodatkowo na pokładzie zostało troszkę miejsca, więc umieściłem tam trzy kości SRAM, też na SPI, a dokładnie 23LC1024:

Mam pewien koncept, do czego je mogę wykorzystać.
Każdy z tych kości ma oczywiście osobny pin Chip Select (aktywne urządzenie na magistrali SPI wybiera się za pomocą tego pinu).
Elementy SMD na płytce starałem się umieszczać w tych bardziej przyjaznych obudowach do lutowania dla początkujących, czyli 0805, a nie np. mniejszej 0603.
Końcowo płytka wyszła tak:

Pełny projekt Eagle do pobrania:
Pliki gerber do utworzenia płytki:
Schemat do pobrania:
Płytki zamówiłem jak zwykle w Chinach - 5 sztuk.
Lutowanie shielda
Płytki przed lutowaniem:


Na początku przylutowałem najtrudniejszy element, czyli sam ENC424 w obudowie TQFP44:

Następnie kolejno małe elementy SMD:

Nie miałem rezonatora kwarcowego 25MHz w odpowiedniej obudowie do montażu powierzchniowego, więc użyłem zwykłego przewlekanego, po prostu odgiąłem mu piny:

Niestety odpowiednie złącza Ethernet (JXD0-0006NL PulseJack produkcji Pulse) mi się skończyły, więc musiałem poradzić sobie odpowiednikiem tego złącza o zgodnym układzie wyprowadzeń lecz bez diod LED RX/TX, czyli J00-0061NL:

Pociągnęło to za sobą potrzebę przylutowania osobnych ledów. Ostatecznie płytka wyszła tak:

Nie przylutowałem wszystkich pamięci na SPI, tylko jedną.
Po wyczyszczeniu z topnika:

Obok Arduino UNO (tego, co użyłem do testów z tematu):

Jak na razie zlutowałem dwie sztuki mojego shielda, zostało mi kilka PCB, chętnych zapraszam na PW.
Test obsługi pamięci 23LC1024
Przed przejściem do tematów powiązanych z ENC424J600 sprawdziłem czy pamięć SRAM 23LC1024 na pokładzie płytki działa. Pamięć ta podłączona jest też na SPI, ma jedynie osobny pin SS (tzw. Chip Select) pozwalający wybrać z którym peryferium na płytce w danym momencie Arduino się komunikuje. Właściwie to na PCB jest miejsce na trzy sztuki 23LC1024, ale ja przylutowałem tylko jedną.
Do obsługi 23LC1024 użyłem biblioteki stąd:
https://forum.arduino.cc/index.php?topic=182918.0
Biblioteka w załączniku:
Pełny kod testowego kodu z biblioteki (nie modyfikowałem go; jest dobry taki jaki jest; zmieniłem tylko pin SS na 8):
Code: c
Rezultat w Serial Monitor:


23LC1024 działa - testy zapisu/odczytu wykonują się poprawnie.
Biblioteka obsługi ENC424J600 dla Arduino UNO
Biblioteki do obsługi ENC424J600 nie musiałem samodzielnie pisać - na Githubie istniała już gotowa, UltratronicsEthernet, autorstwa brupje. To jest właśnie urok Arduino, że praktycznie do większości nieco bardziej popularnych układów są już gotowe rozwiązania.
Użyta biblioteka jest dostępna tutaj:
https://github.com/brupje/UltratronicsEthernet
Kopia zapasowa repozytorium do pobrania:
Bibliotekę dodaje się do Arduino poprzez Sketch->Include Library->Add .ZIP Library
Biblioteka ta tutaj stanowi przerobioną wersję ogólnie znanej biblioteki Ethernet dla Arduino. Po prostu autor przeportował ją pod ENC424.
Tutaj jest dokumentacja pierwowzoru, który był dla modułów W5100 itp:
https://www.arduino.cc/en/reference/ethernet
Moje poprawki biblioteki UltratronicsEthernet
Niestety po kilku testach okazało się, że działa mi z tej biblioteki tylko TCP. DNS wcale nie odpowiadał, DHCP też nie, a nawet nie działało wysyłanie pakietów po UDP.
Zacząłem sprawdzać i debugować, co może być nie tak.
Szybko doszedłem do wniosku, że pierwszy pakiet protokołu DHCP, tzw. DHCP Discovery wygląda tak:
1A 68 D3 93 B6 E7 BE 97 B5 5A BF EB 3B DA DB E0 27 DC 25 16 3D 32 AD 88 3E A4 6 31 97 B9 8B 2F A0 54 1 BC 29 38 C8 B9 B2 EF 1 1 6 0 0 0 3 31 0 0 80 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 BA A
A raczej na pewno nie powinien tak wyglądać - zgodnie z dokumentacją protokołu DHCP pierwszy pakiet powinien zaczynać się od 0xFF 0xFF 0xFF 0xFF, czyli 255.255.255.255, czyli adresu rozgłoszeniowego. Ciąg dalszy pakietu (od 1 1 6 0 0 3 31) wygląda z kolei okej. Są to kolejno DHCP_BOOTREQUEST (1), DHCP_HTYPE10MB (1), DHCP_HLENETHERNET (6), DNS_HOPS (0).
Kolejne testy pokazały, że "1A 68 D3 93 B6 E7 BE 97 B5 5A BF EB" itp. to tak naprawdę są śmieci z pamięci. W bibliotece był błąd na skutek którego nagłówek pakietu IP nie był przesyłany do ENC424.
Naprawiłem to poprzez dopisanie kodu który przed wysłaniem pakietu ponownie wysyła jego bajty poprzez SPI do ENC, choć myślę że można by to jeszcze usprawnić.
Od tego momentu pakiet Discovery od DHCP zaczął wyglądać poprawnie, DHCP i UDP ruszyło.
Oprócz tego w kodzie nie spodobał mi się ten warunek:
Code: c
Usuwał on nieco dłuższe pakiety. Zmieniłem wartość len na nieco większą, choć tu też jest problem z ilością pamięci RAM na Arduino Mimo wszystko od tego momentu biblioteka stała się w pełni użyteczna. Po prostu trzeba pamiętać o limitacjach platformy z której się korzysta.
Zmodyfikowana przeze mnie bieżąca wersja biblioteki (to tej wersji użyłem do przykładów z tematu):
Przykład ENC424J600 na Arduino nr 1 - przypisujemy IP, pingowanie
Najprostszy serwer w bibliotece UltratonicsEthernet można zrealizować tak:
Code: c
Ważne jest o tym, by pamiętać o wywoływaniu Ethernet.maintain() możliwie często, gdyż funkcja ta obsługuje zdarzenia powiązane z siecią, nawet zapytania ping.
Oczywiście wartości:
- IPAddress myIP(192,168,0,126); - adresu IP płytki
- IPAddress myDNS(8,8,8,8); - adresu DNS
- IPAddress myGW(192,168,0,1); - adresu gateway/bramy domyślnej
- IPAddress mySN(255,255,255,0); - maski sieciowej
powinny być zgodne z naszą siecią do której podłączamy płytkę, możemy je łatwo poznać np. na Windowsie używając komendy ipconfig /all.

Widoczność płytki na naszej sieci można sprawdzić z poziomu Windowsa za pomocą komendy 'ping <IP_PLYTKI>', rezultat poniżej:

Przykład ENC424J600 na Arduino nr 2 - serwer TCP echo
W oparciu o kod z poprzedniego akapitu można zrobić prosty serwer TCP echo, czyli serwer który zwróci nam to co do niego wysłaliśmy. Serwer będzie również drukować odebrane pakiety na UART, byśmy mogli zweryfikować w Serial Monitor co się dzieje.
Code: c
(w przykładach tej biblioteki na githubie też macie serwer echo, ale zrealizowany inaczej, używający malloc i free)
Do takiego serwera możemy podłączyć się poprzez TCP. Najprościej chyba jest użyć do tego programu Putty w trybie Raw:

Rezultat testów w Putty:

Rezultat w terminalu:

Przykład ENC424J600 na Arduino nr 3 - prosty klient DNS
DNS (Domain Name System) jest usługą na której opiera się cały internet jaki znamy - służy on do zamiany nazwy hosta (np. elektroda.pl) na adres IP (np. 104.109.65.140). Mój shield dla Arduino też jest do tego zdolny, co jest przedstawione w przykładzie poniżej:
Code: c
Rezultat działania (dla hostu elektroda.pl):

Rezultat działania (dla hostu google.com):

Przy okazji zrobiłem też eksperyment - zmieniłem adres serweru DNS (wcześniej: 8.8.8.8) na adres IP mojego komputera i za pomocą Wiresharka sprawdziłem co przyjdzie. Oto rezultaty:

Jak widać Wireshark poprawnie wykrył, że nadszedł pakiet DNS. Moja maszyna go nie obsłużyła, bo nie mam postawionej na niej usługi DNS, ale z pewnością by mogła.
Przykład ENC424J600 na Arduino nr 4 - DHCP czyli automatyczne przypisywania konfiguracji IP dla Arduino
Kolejną rzeczą wartą sprawdzenia jest DHCP - Dynamic Host Configuration Protocol. DHCP pozwala klientom automatycznie pobrać konfigurację sieci od routera. Nie musimy im sami konfigurować IP, maski, bramy domyślnej, itp, wszystko ustawia się samo.
Poniżej przykład pobierającego konfiguracje przez DHCP:
Code: c
Rezultat w terminalu:

Rezultat pingowania nadanego IP:

Rezultat pracy DHCP też można podejrzeć na niektórych routerach, w historii zdarzeń:

Oczywiście, jak zmienimy w kodzie MAC na inny to przypisany zostanie nam inny adres IP (tamten wcześniej użyty będzie mieć jeszcze lease):
Code: c
Inny adres IP przypisany przez router:


Przykład ENC424J600 na Arduino nr 5 - DHCP + DNS
Teraz pora na połączenie dwóch poprzednich przykładów. Program pobiera automatycznie konfiguracje sieci a potem określa IP hostów z tablicy. Kod:
Code: c
Do listy hostów dodałem tutaj adres nieistniejącej strony, by przedstawić co wtedy wyświetli program.
Rezultat działania kodu:

Przykład ENC424J600 na Arduino nr 6 - klient UDP usługi NTP
NTP (Network Time Protocol) to prosty protokół internetowy pozwalający na synchronizację czasu między urządzeniami. Opiera się on na UDP i w zasadzie ogranicza się do wysłania zapytania do serwera NTP i odebrania odpowiedzi. Można go bardzo prosto użyć na Arduino.
Serwerów NTP w sieci jest mnóstwo i są do użycia jak najbardziej za darmo, można znaleźć ich listę tutaj:
https://www.pool.ntp.org/zone/europe
Wartość czasu w NTP wyrażona jest za pomocą 32-bitowego integera (jest to ilość sekund od 1 stycznia 1900) , którego musimy jeszcze odpowiednio odkodować, ale na szczęście mamy do tego gotowe mechanizmy z biblioteki Arduino time.h.
Należy tu pamiętać jednak, że time.h na Arduino jest nieco inne niż te np. na Windowsie, o czym mówi sama dokumentacja AVR-GCC:
Quote:
Though not specified in the standard, it is often expected that time_t is a signed integer representing an offset in seconds from Midnight Jan 1 1970... i.e. 'Unix time'. This implementation uses an unsigned 32 bit integer offset from Midnight Jan 1 2000. The use of this 'epoch' helps to simplify the conversion functions, while the 32 bit value allows time to be properly represented until Tue Feb 7 06:28:15 2136 UTC. The macros UNIX_OFFSET and NTP_OFFSET are defined to assist in converting to and from Unix and NTP time stamps.
Ale to żaden problem. Poniżej przedstawiam jak można odebrać czas NTP i wyświetlić go na 3 różne sposoby:
- sposób pierwszy - funkcja ctime
- sposób drugi - 'na piechotę', bez użycia funkcji bibliotecznych
- sposób trzeci - gmtime
Pełny kod:
Code: c
W powyższym kodzie polecam zwrócić uwagę na dwie rzeczy.
- NTP_OFFSET - jest to stała z time.h, z AVR-GCC, służąca do poprawnej konwersji czasu ze standardu NTP do tego co mamy na Arduino
- TIMEZONE_GMT_OFS - jest to zmienna określająca przesunięcie godziny (strefę czasową), która jest zdefiniowana na początku kodu
Rezultat działania kodu:

Na powyższym zrzucie ekranu widać rezultaty dwóch zapytań NTP pomiędzy którymi był odstęp czasowy około 5 sekund. Zapytania NTP warto jest wysyłać co jakiś czas, albo przynajmniej sprawdzać ich rezultat, bo protokół UDP jest bezpołączeniowy i nie daje żadnej gwarancji, że pakiet dotrze do celu.
Przykład ENC424J600 na Arduino nr 7 - serwer TCP kalkulator
Poprzedni mój przykład serwera TCP ("serwer TCP echo") można łatwo zmodyfikować tak, by zademonstrować parsing danych wysyłanych przez klienta oraz konwersje napisu (typ char) na liczbę zmiennoprzecinkową (float) za pomocą funkcji atof.
W tym celu zrobiłem prosty kalkulator, który odbiera tekst w formacie "2+2" i zwraca wynik tak opisanego działania matematycznego. Wspiera cztery działania - dodawanie, odejmowanie, dzielenie i mnożenie.
Pełny kod:
Code: c
Najważniejszym fragmentem powyższego kodu jest pętla for która znajduje w napisie znak oraz funkcja pomocnicza 'mySubStrFloat' która wyciąga z napisu fragment reprezentujący daną liczbę. Kod nie zawiera żadnego sprawdzania błędów.
Do tego serwera TCP można łatwo podłączyć się poprzez Putty w trybie RAW (czyli czyste TCP, bez HTTP). Rezultat testów w Putty:

Widać, że Arduino przy wyświetlaniu floatów zaokrągla do 2 miejsc po przecinku, ale to już jest kwestia tamtejszej implementacji atof a nie mojego kodu.
Przykład ENC424J600 na Arduino nr 8 - serwer HTTP czyli nasza strona WWW
Przykład ten to chyba najbardziej charakterystyczne zastosowanie ENC28J60 (i użytego tutaj ENC424J600) wśród hobbystów. Nasza własna strona WWW, w pełni na Arduino. Użyty protokół tutaj to oczywiście HTTP (który opiera się na TCP i korzysta z reguły z portu 80), a sam język strony WWW to HTML.
Kod tego przykładu bazowałem na dokumentacji Arduino https://www.arduino.cc/en/Tutorial/WebServer
Jedynie nieco go ulepszyłem i dodałem linijkę Ethernet.maintain(), która w tej wersji biblioteki ENC424 jest niezbędna do wywołania ręcznie.
Pełny kod poniżej:
Code: c
Rezultat w przeglądarce:

Rezulat w serial monitor (widać tutaj jak wygląda zapytanie wysyłane przez przeglądarkę do Arduino, słynne HTTP GET):

Powyższy kod jeszcze dodatkowo wyświetla na stronie odczyt z wejść analogowych Arduino (piny A1, A2, itp.). Aby ten odczyt miał sens, należy coś do nich podłączyć - na przykład potencjometry:

Odczyty dla różnych ustawień potencjometrów:



Przykład ENC424J600 na Arduino nr 9 - klient HTTP (wysyłamy zapytanie GET)
Tutaj pokażę jak możemy wysłać zapytanie GET do serwera HTTP. GET jest to zapytanie o konkretną stronę internetową/dokument/plik na serwerze. GET jest wysyłane jako czysty tekst, poprzez protokół TCP.
Dla przykładu tutaj wyślę GET do serwera który zwraca sam nasz adres IP (oczywiście też z nagłówkiem HTTP OK).
Serwer ten to http://ipinfo.io/ .
Link do usługi zwracającej samo IP jako tekst w HTTP: http://ipinfo.io/ip
Przy okazji też po raz kolejny użyję tutaj usługi DNS. W kodzie podam nazwę domenową serwera, a biblioteka Ethernet sama zamieni ją na IP.
Poniżej pełny kod:
Code: c
Rezultat działania kodu:

Warto zwrócić uwagę, że odpowiedź serwera najpierw zawiera nagłówek HTTP (HTTP kod 200 OK), a potem dane które już są wyświetlane w przeglądarce.
Przykład ENC424J600 na Arduino nr 10 - klient HTTP i argumenty zapytania GET
Zapytanie GET z protokołu HTTP omówione w poprzednim akapicie może posiadać argumenty. Zapisane są one w samym linku, po znaku '?', za pomocą znaków '=', a kolejne argumenty oddzielone są od siebie '&'. W taki sposób:
https://www.elektroda.pl/rtvforum/privmsg.php?mode=reply&p=5758394
Tutaj bazowy URL to jest:
https://www.elektroda.pl/rtvforum/privmsg.php
Reszta natomiast to są argumenty:
mode=reply&p=5758394
Wartość argumentu 'mode' to 'reply', a wartość argumenty 'p' to 5758394.
Przedstawię tutaj, jak takie argumenty można wysłać z poziomu Arduino.
Potrzebny do tego będzie też serwer WWW, na którym uruchomimy skrypt PHP który odbierze te argumenty i przetworzy.
Taki serwer możemy postawić sami na własnej maszynie (np. za pomocą Xampp) albo kupić w sieci, albo... skorzystać z któregoś z darmowych serwerów z PHP, takie usługi też są.
Dla przykładu zrealizujemy tutaj prosty kalkulator - skrypt PHP odbierze dwie liczby i zwróci wynik operacji na nich.
Skrypt powinien zwracać czysty tekst, a nie dokument HTML, więc dodatkowo zmienimy jego content-type.
Oto skrypt:
Code: php
Teraz potrzebny też będzie kod na Arduino, który wyśle poprzez GET wartości zmiennych 'pierwsza' i 'druga'.
Dane te umieszcza się w samej ścieżce do pliku w zapytaniu GET - przykład kodu poniżej:
Code: c
Do liczb w kodzie powyżej użyłem typu int, więc musiałem jeszcze zamienić je na napis (tablicę charów) za pomocą sprintf.
Rezultat działania w Serial Monitor:

Kod działa - argumenty są poprawnie wysyłane i odbierane przez skrypt PHP po stronie serwera. Na Arduino można by się pokusić o lepszy parsing odpowiedzi HTTP, ale to już zależy do czego chcemy wykorzystać GET. Jeśli chcemy np. za pomocą GET wysyłać wyniki pomiarów do serwera WWW i tam zapisywać je w bazie danych SQL, to w zasadzie samej odpowiedzi na GET nawet nie musimy parsować.
Na koniec jeszcze mogę wspomnieć, że wysyłanie zapytań GET można testować poprzez program Putty - po prostu wpisuje się w nim treść zapytania. Wygląda to tak:

Przykład ENC424J600 na Arduino nr 11 - klient HTTP - zapytanie GET reverse geocoding
Reverse geocoding jest to proces zamiany koordynatów (szerokość i długość geograficzna) na słowny opis danej lokacji (nazwa miasta, ulicy, itp).
W internecie dostępne są różne usługi oferujące reverse geocoding - część z nich jest płatna, część jest darmowa (ale z reguły ma limity zapytań oraz wymaga rejestracji w celu zdobycia klucza API), część korzysta z HTTPS a część z HTTP.
Tutaj przedstawię jak można użyć takiej usługi na przykładzie geocode.arcgis.com . Strona ta oferuje reverse geocoding bez potrzeby rejestracji i po czystym HTTP, zapytanie GET.
Dokumentację tej usługi możecie znaleźć tutaj:
https://developers.arcgis.com/rest/geocode/api-reference/geocoding-geocode-addresses.htm
Zasadniczo całe użycie tej usługi sprowadza się do wysłania jednego GETa do serwera z parametrami zakodowanymi w samym URL, np takiego:
http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/reverseGeocode?f=pjson&featureTypes=&location=-117.205453%2C34.037988
Można sprawdzić jak to działa w przeglądarce - kliknąć na link poniżej:
http://geocode.arcgis.com/arcgis/rest/service...reTypes=&location=-117.205453%2C34.037988
Dodatkowo sprawdziłem też działanie tego w Putty, by określić jaki nagłówek GET muszę wysłać.
Opracowałem następujący kod:
Code: c
Powyższy kod najpierw określa IP serwera geocode za pomocą DNS, a potem wysyła do niego zapytanie co znajduje się na pozycji GPS -117.205453 34.037988.
Rezultat działania:


Jak widać przykład reverse geocoding działa poprawnie - zwraca pełny zestaw informacji na temat danego punktu na mapie. Można potem te informacje parsować i wyciągnąć z nich to, co nas konkretnie interesuje.
Co można by zrobić lepiej, uwagi
Przedstawioną tu płytkę, przykłady a nawet bibliotekę można by znacznie ulepszyć.
- płytkę można przerobić tak by elementy były w obudowach 0603 a nie (głównie) w 0805 i coś jeszcze na niej zmieścić
- w bibliotece można ulepszyć komunikację z ENC424 poprzez SPI (tam był błąd związany z UDP; naprawiłem go wpisując osobno każdy bajt, a można też je wpisać po kolei; nie ulepszyłem tego bo i tak już działało, a czas na optymalizację jeszcze mam)
- w niektórych przykładach przydałoby się lepiej parsować odpowiedź GET i nie zamykać przedwcześnie połączenia (może się zdarzyć, że available() zwróci 0 a potem dopiero dojdzie ciąg dalszy danych)
- w bibliotece można by dokończyć (chyba nie są sprawne) #define/#ifdef pozwalające wyłączyć np. całkiem DHCP lub DNS gdy go nie używamy (DHCP jest tak podpięte do biblioteki w funkcji tick()/maintain() że nawet gdy go nie używamy to zajmuje pamięć)
Podsumowanie
Projekt okazał się nieco trudniejszy niż myślałem - początkowo założyłem, że biblioteka UltratonicsEthernet dla Arduino będzie w pełni funkcjonalna, a jednak musiałem ją poprawiać. Na szczęście po kilku godzinach debugowania i wypisywania pakietów na UART udało mi się znaleźć błąd i wszystko ruszyło.
Na koniec jeszcze podkreślę, że użyta tu biblioteka jest niemalże identyczna ze strony użytkownika z normalną biblioteką Ethernet dla Arduino, więc przygotowane przykłady mogą tez się przydać jak używacie innego układu niż ENC424 będący tematem tego postu.
Cool? Ranking DIY