[RETRO] Bezprzewodowy interfejs SCPI do Meratronik V543

Oscyloskopy, multimetry, generatory, nie tylko z najwyższej półki
tasza
Expert
Expert
Posty: 861
Rejestracja: czwartek 12 sty 2017, 10:24

[RETRO] Bezprzewodowy interfejs SCPI do Meratronik V543

Postautor: tasza » sobota 19 maja 2018, 18:55

#slowanawiatr

♬ ☘ Moja muzyka do kodowania ♬ ♬ ♬ ☘
♫ ♩ ♪ Find Me ⚡ ☘ ⚡ Wings Of Love ♪ ♩ ♫
https://youtu.be/uq8wRyNV9NA
 

pięćdziesiąt twarzy Greya
 
Obrazek
 
Z lektury wzmiankowanej książki podstawowy wiosek dla mnie taki, że monotonia czy wręcz nuda to znani wrogowie udanej zabawy.

W końcu jak długo i na ile sposobów można wiązać się kablem? 

A skoro tematyka przewodowego Ethernetu została już poruszona na forum, więc w ramach urozmaicenia opisywany dalej interfejs SCPI do Meratronika V543 bazuje na rozwiązaniu bezprzewodowym. Podstawą jego jest komputerek Raspberry PI Zero w wersji z WiFi. Wybór platformy był dość prosty: o układzie ESP8266 napisano w majowej EdW, więc napoczętego przez kogoś tematu nie będę już drążyć. Do wszelkich shieldów z WiFi dedykowanych Arduino podchodzę póki co ze sporą rezerwą, ten wariant zatem także odpada. I tak pozostaje relatywnie tanie i posiadające ogromne wsparcie społecznościowe Raspberry PI, do zastosowań ‘pod zabudowę’ wersja Zero z WiFI jest wręcz idealna. Niewielka gabarytowo, posłuszna, wdzięczna w oprogramowaniu i za jedyne pięć dyszek.
 
Obrazek
 
niepozorna Malinka
 
W formie garstki linków wskazania na opisy co i jak skonfigurować, a ogarnięcie świeżego sklepowego modułku i przygotowanie go do dalszych prac zajmie raptem jeden wieczór. Na kolejnych etapach pracy korzystałam z tych materiałów z sieci:
 
:arrow: https://www.raspberrypi.org/documentati ... s/linux.md
:arrow: https://techfreak.pl/raspberry-pi-zero- ... acja-wifi/
:arrow: http://www.science.smith.edu/dftwiki/in ... spberry_Pi
:arrow: http://www.science.smith.edu/dftwiki/in ... spberry_Pi
:arrow: http://pi4j.com/pins/model-zero-rev1.html
:arrow: https://cdn.sparkfun.com/assets/learn_t ... Zero_1.pdf
 
Jeżeli póki co nie chcemy nic lutować do złącz Maliny, a nie posiadamy na podorędziu kabelka USB OTG i Mini HDMI to aby dostać się do konsoli systemu pozostaje nam opisywana w linkach powyżej partyzantka z przekładaniem karty do czytnika w komputerze i edytowaniem plików na karcie.
 
Obrazek
Obrazek
Obrazek
 
Gdy ktoś pracuje na co dzień z Linux to wszelkie narzędzia ma pod ręką niejako z pudełka i sprawa nie jest skomplikowana. Istnieje też inna alternatywna ścieżka - wstępne skonfigurowanie świeżego systemu na dużej Raspberry PI, przy użyciu klawiatury i monitora czy nawet telewizora, potem kartę można przełożyć do Zero. 
 
Obrazek
 
Ja poszłam tą właśnie drogą, ssh i wifi ustawiłam sobie wygodnie na większej siostrze, operacje typu `expand filesystem` i wgranie świeżych paczek systemowych, git i reszta – już w natywnym środowisku sprzętowym PI Zero.
 
I jeszcze jedno - w trakcie rozkładania obrazu systemu na karcie przy pomocy polecenia `dd` tak naprawdę nie wiadomo co się dzieje. Programik dd nie należy do specjalnie wylewnych, a sam proces wgrywania zajmuje dłuższą chwilę.  Warto wtenczas otworzyć sobie na boczku drugi terminal, wykonać `top` albo `ps –A` aby pozyskać identyfikator procesu dd, a potem wysyłać mu sygnał USR1, o na przykład tak:
 
Obrazek
 
W ten sposób zagadnięte dd wyświetli na niemej dotychczas konsoli informacje ile aktualnie już pracy wykonał, a przede wszystkim – jak nam odpowie, to znaczy że nic tam nie zawisło. U mnie akurat to było pomocne, bo wiekowy nieco czytnik renomowanej firmy Tesco ma problem ze stykiem do wykrywania karty SD i czasem w trakcie dłużej trwających operacji potrafi wyciąć psikusa. Na koniec cieszymy się maleńką diodką na PI Zero, której filuterne pomrugiwanie oznacza ładowanie Linuksa, inicjację systemu i jest zaproszeniem do dalszej zabawy.
 
Obrazek
 
użytkowanie wieczyste
 
W moich realiach Malina ma nadany stały adres IP, trwałą dzierżawę IP zapewnia odpowiedni konfiguracja serwera DHCP wbudowanego w domowy router i rozpoznająca Malinkę po adresie MAC. Tak samo rozpoznawany jest Rigol-Cukierek. Drobna edycja pliku /etc/hosts zapewnia widoczność modułku po nazwie, nie ma sensu dla takiego drobiazgu bawić się w lokalny DNS.
 
Obrazek
 
Obrazek
 
Mając dostęp do systemu przez ssh jesteśmy praktycznie w domu i dalsze prace będą koncentrowały się tylko i włącznie na sprawach związanych z interfejsem do Meratronika. Dobrze jest doinstalować sobie pakiet proftpd wtedy dowolnym , ulubionym klientem ftp możemy komfortowo nawigować po systemie plików Maliny, a także edytować zdalne pliki tekstowe jeżeli nasz ulubiony edytor to potrafi (na przykład Kate z KDE). Drugi przydaś to git, ja programik pisałam bezpośrednio na Malinie, a odrobina pecha przy wyłączaniu zasilacza i pstryk - po filesystemie. Tak więc git add/commit/push pozwalały zachować spokój ducha, ponieważ prace były bezpieczne, poza Maliną.
 
wąż kusiciel kontra C
 
Przyznam, dłuższą chwilę zastanawiałam się w czym popełnić oprogramowanie komunikacyjno-sterujące, a możliwości jest całkiem sporo.  W domyślnej instalacji Linuksa na PI mamy język C/C++ (gcc v.6.3), można łatwo doinstalować Free Pascal, jest też Python, choć co odrobinę zaskakujące w wersji 2.7. I ten Python mnie kusił straszliwie, och jak mocno. Tym bardziej, że miałabym wsparcie u autora tej oto cudnej zabawki :arrow: https://www.sbprojects.ga/projects/pi-epsim/ , tam emulatorem pamięci steruje właśnie PI Zero i program w Pythonie. Robiąc bliźniaczy projekcik miałabym relatywnie łatwiej niż walcząc z tematem od zera. Tylko że zadziałała zasada `czym skorupka i tak dalej` i oko me zawisło na kultowej jak dla mnie książce `Programowanie zastosowań sieciowych w systemie Unix`, która praktycznie w całości bazuje na języku C.  No i dylemat się rozwiązał.
 
Obrazek
 
Nie zmienia to faktu, że połączenie Python/GPIO i tak muszę rozpoznać detalicznie, do pisania przydasiów na kolanie wydaje się być bardzo efektywne vide wzmiankowany emulator Sana, który mi ciągle nie daje spokoju.
 
zapoznanie z GPIO
 
Dostęp do GPIO Maliny wcale nie jest skomplikowany, a jeżeli ktoś wcześniej bawił się w Arduino to już w ogóle w temat wejdzie bezboleśnie. Kluczową sprawą jest pobranie sobie na Malinkę pakietu WiringPI :arrow: http://wiringpi.com/ i skompilowanie bibliotek. Do wywołania kompilatora/linkera dodajemy -lwiringPi , aplikacje linkują się bez problemu. Interfejsik mój prosty, to i funkcji bibliotecznych jeno garstka w użyciu, oto one:
 
* pinMode ( pin, kierunek ) - konfiguracja wej/wyj
* digitalWrite( pin, stan ) - zapis
* digitalRead( pin ) - odczyt
 
potem pojawiła się jeszcze funkcja instalująca handler przerwania dla danego pinu IO czyli:
 
* wiringPiISR( pin, rodzaj_pobudzenia, adres_handlera )
 
Prosty programik, który nabazgrałam w międzyczasie generował falę prostokątną na pinie 0, cały kod sprowadza się raptem do poniższych linijek:

Kod: Zaznacz cały

 
   pinMode ( 0,   OUTPUT );
   while ( 1 ) {
       digitalWrite( 0, HIGH );
       digitalWrite( 0, LOW );
   }
 
 
Obrazek
Obrazek
Obrazek
 
Jak widać dostęp do GPIO jest intuicyjny, a programowo można generować całkiem szybkie przebiegi.
 
logika na poziomie
 
Fakt to ogólnie znany, że malinowe GPIO pracuje z poziomami logicznymi charakterystycznymi dla logiki 3.3V i nie jest ‘five volts tolerant’. Dla odmiany logika mojego neonowego Meratronika to klasyczny TTL, interfejs z układami 74LS165 takoż.  Niezbędna jest zatem konwersja 5<->3v3 dla linii interfejsu, a ową wykonałam przy pomocy łatwego do kupienia modułku do zmiany poziomów.

:arrow: https://botland.com.pl/konwertery-napie ... ololu.html
 
Obrazek
Obrazek
Obrazek
 

W tym przypadku modułek-konwerter został spreparowany do pracy z kątowymi złączami igłowymi i kabelkami, tak było mi najłatwiej i w sumie najelastyczniej – w końcu to jeden wielki eksperyment i zmiany są na porządku dziennym. Robiąc docelowe rozwiązanie taki modułek najlepiej umieścić w podstawce DIL lub wręcz wlutować w płytkę.
 
kanapka z Maliną
 
Zacznę od  tego, że schemat przyłączenia interfejsu do PI Zero wygląda jak poniżej:
 
Obrazek
 
Konwerterek, który posiadam ma cztery kanały, pokrywa nadawane prze PI sygnały /LINE_LOAD,  LINE_CLK jak i odczytywane LINE_DATA oraz LINE_READY. Świadomie zrezygnowałam z obsługi LINE_START, niech mierniczek spokojnie pracuje sobie we własnym rytmie, impulsy na LINE_READY zauważane przez Malinę w postaci przerwań zapewnią odczyt nowych wartości w stosownym momencie i nic nie zostanie przegapione.
 
Kolejna rzecz to sygnalizacja pracy interfejsu. Oczywiście jak zobaczymy PI w naszej sieci lokalnej to już jest nieźle, a jak zalogujemy się do niej via ssh to rewelacja. Ale w trakcie normalnego użytkowania chyba warto wiedzieć czy w ogóle programik komunikacyjny ruszył, czy odczytuje miernik i czy jest komunikacja z PC na poziomie komend SCPI. Do tego celu służą widoczne na schemacie dwie diody świecące, podparte tranzystorami i zapięte go pinów 4 i 5. Ich miganie oznacza kolejne cykle odświeżenia danych przez miernik oraz kolejne obsługiwane polecenia SCPI. Nieustanna błyskoteka na tyle miernika oznacza zatem, że całość pracuje w miarę poprawnie.
 
Dalej garść zdjęć z kolejnych etapów melanżu Maliny z podrutowanym interfejsem do V543.
 
Wstępne przymiarki grzebyczka gold-pin
 
Obrazek
Obrazek
 
Okazało się, że otworki z Malinie są zbyt małe i aby przewlec śrubki M3 muszę je nieco poszerzyć, zatem pilnik-iglak w dłoń. Miałam stres wtedy, taka drobniutka lutowanka na płytce i ostre narzędzie.
 
Obrazek
 
Po kilku przymiarkach Malina zawisła na słupkach dystansowych na płytce interfejsu, tak na kanapkę. Orientacja PI jest taka, aby złącze zasilające mikro USB było w dół, to w moich realiach skutecznie zminimalizuje ryzyko wygięcia lub odłamania złącza z płytki PI.
 
Obrazek
Obrazek
Obrazek
Obrazek
 
Obowiązkowy LED od zasilania. Może i zabawne, ale komórkowa ładowarka z której zasilane jest PI nie ma sygnalizacji, a sami ledzik na PI maleńki i przysłonięty drutami, lampka na boku w tym przypadku akurat jest dla mnie zasadna
 
Obrazek
 
Diody sygnalizujące cykle odczytu V543 oraz komunikację SCPI są zamontowane na brzegu, widać je w miarę dobrze choć i tak trzeba zapuścić żurawia na tył urządzenia.
 
Obrazek
Obrazek

Test diodek na sucho:

https://youtu.be/IccJuTZlHwI

I podczas normalnej pracy interfejsu - prawa to odczyty, lewa - polecenia SCPI z terminala

https://youtu.be/4n_aE9SOfYo
 
A tu dygresja nie na temat – w pudełku taki oto ledzik z czasów PRL znalazłam, prostokątny, czerwony, CEMI bodajże. Ale mi się go szkoda zrobiło, bo nielutowany nigdy i wrócił do siebie.
 
Obrazek
 
Konwerter 5-3v3 został zawieszony na króciutkich specjalnie ku temu spreparowanych kabelkach połączeniowych. Całość jest w miarę bezboleśnie rozbieralna gdyby zaszła jakaś potrzeba poprawek czy przeróbek, a jednocześnie dość pakowna, a pomimo konstrukcji natury powietrznej nic nie dynda ani się nie majta.
 
Obrazek
Obrazek
Obrazek
Obrazek
Obrazek
Obrazek
Obrazek
Obrazek
Obrazek
Obrazek
 
Zrobienie zdjęć zadeczka Meratronika z zamontowanym interfejsem wymaga odrobiny akrobatyki ewentualnie wykorzystania lusterka, całość prezentuje się następująco i to jest stan na chwilę obecną docelowy.
 
Obrazek
Obrazek
Obrazek
 
gwara meratronikowa
 
Kod programiku v543.c dostępny jest w lokalizacji :arrow: https://github.com/bienata/piv543scpi/b ... ter/v543.c i proszę o wyrozumiałość, to wersja `na kolanie` i jeszcze rozwojowa.

O detalach implementacyjnych oprogramowania nie będę się tu zbytnio rozwodzić, informacje o programowaniu gniazdek oraz przykłady sieciowych aplikacji klient-serwer można znaleźć w literaturze, choćby w doskonałej pozycji, którą wskazałam na początku tego tekstu. Jeżeli zapoznamy się jakoś ze standardowymi funkcjami socket(), bind(), listen() i accept() to w zasadzie możemy już w sieci zrobić cokolwiek tylko przyjdzie nam do głowy.

Chcę za to poruszyć teraz temat samego definiowania zestawu poleceń SCPI dla multimetru V543, czy jakiegokolwiek innego `customowego` sprzętu, bo tu nie ukrywam miałam pewien problem. 

Pierwsza moja myśl była taka, aby pasujące do urządzenia komendy zapożyczyć sobie z jakiegoś sprzętu, który ma SCPI zaimplementowane, na przykład `DM3000 Digital Multimeter` :arrow: https://dokumente.unibw.de/pub/bscw.cgi ... uelle5.pdf  I w zasadzie byłoby super gdyby nie to, że V543 ma jednak w porównaniu z rzeczonym multimetrem dość ubogie możliwości, zbiór poleceń należałoby ograniczyć, a takie znowu przerzedzenie spowodowało utratę spójności składni i generalnie wyglądało dziwnie. Przejrzenie dokumentacji do kolejnego miernika, tym razem `Fluke 8845` :arrow: http://assets.fluke.com/manuals/8845a___pmeng0200.pdf dało efekt podobny. Nie potrafiłam jakoś wyłuskać sensownego podzbioru poleceń, zawsze wychodziło jakieś pokraczne dziwadło.
 
Pozostało zatem spreparowanie własnej autorskiej wersji dialektu SCPI, dedykowanej dokładnie mojemu mierniczkowi V543. I tu kłopot polega na tym, że trzeba zdecydować w jakiej części obróbka danych ma być po stronie miernika, a w jakiej po stronie aplikacji klienckiej, która z tych danych skorzysta.
Przykład wariantowości sytuacji:
* możemy odesłać surową binarną ramkę, która odzwierciedla stan wyświetlacza, bity zakresu, polaryzacji i tryby pracy – dana w postaci unsigned long. 
* możemy też na poziomie interfejsu ładnie spreparować wynik pomiaru i odesłać na przykład wartość napięcia w mV i minusem gdy ujemne w formie napisu ASCII.

I tu powstaje pytanie – jak będzie używany interfejs SCPI? Czy może systemowo? I z miernikiem będzie komunikować się inne urządzenie lub aplikacja? A może jednak na żywca z konsoli lub prostymi skryptami będzie te polecenia wydawał człowiek, czyli dalsze przetwarzanie będzie na poziomie białkowym? Tego nie wiadomo przecież, definiując składnię trzeba wypracować coś po środku. SCPI jest (w mojej opinii) interfejsem typu maszyna-maszyna a nie człowiek-maszyna, choć prostota poleceń i czytelna forma nie wykluczają jego manualnej obsługi (vide `Rigol na smyczy`). Tak po prawdzie to mając podobne zagwozdki warto sięgnąć po opracowanie opisujące standard, na przykład: :arrow: http://www.ivifoundation.org/docs/scpi-99.pdf Finalnie stanęło na tym, że mój Meratronik będzie rozumiał następujące autorskie polecenia:
 

Kod: Zaznacz cały

TCommand scpiCommands[] = {
    {   "*idn?",              &handlerIdn },   
    {   ":meter:mode?",       &handlerMode },
    {   ":meter:v:range?",    &handlerVRange },
    {   ":meter:r:range?",    &handlerRRange },
    {   ":meter:raw?",        &handlerRawData },
    {   ":meter:display?",    &handlerDisplay },
    {   ":debug:exit",        &handlerExit },
    {   NULL ,                NULL }
};


*idn?
Identyfikacja urządzenia, numer seryjny przepisany z obudowy oraz copyright aby wyglądało na profeskę, przynajmniej dla tych, co się nie znają.
 
:meter:mode?
Polecenie zwraca aktualny tryb racy multimetru lub błąd w przypadku nie wciśnięcia żadnego z przycisków funkcyjnych.
Zwraca wartość jest w formacie n|xx , gdzie n – identyfikator trybu wynikający z kombinacji bitów na tylnym złączu, xx –literały { R, AC, DC }, czyli w kodzie jest:

Kod: Zaznacz cały

const char *pszModeDesc[] = {
      "error",    // 0
      "R",        // 1
      "AC",       // 2
      "error",    // 3
      "DC"        // 4       
};

 
:meter:v:range?
Polecenie zwraca aktualnie ustawiony zakres pomiarowy napięcia lub błąd gdy miernik nie jest w trybie VAC lub VDC.
Zwraca wartość jest w formacie n|xxxx|ddd na zasadach jak powyżej, dozwolone wartości zgodnie z definicją:

Kod: Zaznacz cały

TRangeInfo volRanges[] = {
    {   "100V",       100   },  //0
    {   "1V",         10000 },  //1
    {   "1000V",      10    },  //2
    {   "10V",        1000  },  //3
    {   "100mV",      100   },  //4
    {   "error",      1     },  //5
    {   "error",      1     },  //6
    {   "error",      1     }   //7
};

 
:meter:r:range?
Polecenie zwraca aktualnie ustawiony zakres pomiarowy rezystancji lub błąd gdy miernik nie jest w trybie R.
Zwraca wartość jest w formacie n|xxx|ddd na zasadach jak powyżej, a dozwolone wartości takie:

Kod: Zaznacz cały

TRangeInfo resRanges[] = {
    {   "100kΩ",      100   },  //0
    {   "1kΩ",        10000 },  //1
    {   "error",      1     },  //2
    {   "10kΩ",       1000  },  //3
    {   "error",      1     },  //4
    {   "1MΩ",        10000 },  //5
    {   "error",      1     },  //6
    {   "10MΩ",       1000  }   //7
};

 
W obu przypadkach ddd - to podzielnik, wynikający z aktualnie ustawionego zakresu, jest podstawą do sformatowania wyniku.

:meter:raw?
Polecenie zwraca 32-bitową liczbę w formie ośmiu cyfr szesnastkowych. Zawartość binarna zgodna z Tabelą 1 z artykułu w EdW 4/2018.
 
:meter:display?
Polecenie zwraca zawartość wyświetlacza w postaci pięciocyfrowej liczby dziesiętnej (bcd) wraz ze znakiem polaryzacji dla pomiarów DC oraz bez znaku dla R i AC. Brak kropki dziesiętnej, wynik trzeba sformatować samodzielnie.
 
:debug:exit
Komenda na użytek wewnętrzny, to zatrzymanie aplikacji, przydaje się zamiast wpisywania `killall v543`  

Jak widać odpowiedzi interfejsu są zrozumiałe dla średnio rozgarniętego operatora, ale i możliwe do obróbki programowej. Wystarczy napis z informacją o zakresie czy trybie potraktować funkcją strtok() czy jej odpowiednikiem dzielącym napis na składniki w/g separatora (u mnie `|`) i mamy osobne wartości do wykorzystania.
 
Proszę też zauważyć, że nie ma w tym zestawie polecenia *rst resetującego urządzenie. No cóż – w moim przypadku załamanie pracy aplikacji automatycznie znieczuli ją na nadchodzące polecenia, więc zdalny restart nie wchodzi w grę. Pomoże tylko interwencja przez ssh lub brutalna manipulacja przy zasilaniu.
 
Na chwilę obecną nie pochylam się zbytnio nad zdarzeniami zachodzącymi w otoczeniu multimetru, więc brakuje obsługi poleceń *ese?, *esr? I tym podobnych.  Można oczywiście zastanowić się nad zapamiętywaniem wystąpienia sygnału OVER wraz ze znacznikiem czasu czy obserwowaniem wartości MIN/MAX. Malina pracująca jako interfejs ma naprawdę sporą moc obliczeniową i można sobie używać.
 
Testy - tu z wywołaniem exit:

Kod: Zaznacz cały

echo ":debug:exit" | nc neonowy 5555
 
Obrazek

Pomiary rezystancji:

testr.sh pisze:

Kod: Zaznacz cały

echo "*idn?" | nc neonowy 5555
echo ":meter:mode?" | nc neonowy 5555
echo ":meter:r:range?" | nc neonowy 5555
echo ":meter:display?" | nc neonowy 5555
echo ":meter:raw?" | nc neonowy 5555

Kod: Zaznacz cały

while true; ./testr.sh; sleep .5; done

Obrazek

Pomiary napięcia:

testv.sh pisze:

Kod: Zaznacz cały

echo "*idn?" | nc neonowy 5555
echo ":meter:mode?" | nc neonowy 5555
echo ":meter:v:range?" | nc neonowy 5555
echo ":meter:display?" | nc neonowy 5555
echo ":meter:raw?" | nc neonowy 5555

Kod: Zaznacz cały

while true; ./testv.sh; sleep .5; done

Obrazek

Na żywo praca interfejsu wygląda tak: 

https://youtu.be/X6LNc4dJ-tI

Aby programik v543 uruchamiał się automatycznie, wystarczy dodać go do /etc/rc.local i mamy samograj.

Podsumowanie i :debug:exit
  
O Raspberry PI napisano już bardzo wiele, więc z moje strony może tylko tyle, że nie ma co demonizować tego systemiku i traktować jako czegoś szczególnie magicznego. To zwykły system mikroprocesorowy bazujący na dość mocnym ARM z linuksem (a'la Debian) na pokładzie, oswojenie go tak, aby skakał przez kijek nie jest jakimś szczególnym wyzwaniem. Ma bardzo dużo zalet i sporo pracy potrafi z nas zdjąć. Ma też swoje upierdliwości, z którymi trzeba się będzie pogodzić gdy kto jednak zdecyduje się pójść w tym właśnie kierunku.
Ważne natomiast jest to, że obcując z Raspberry PI możemy w pełni wykorzystać swoje dotychczasowe doświadczenia z Linux zdobyte na domowej, dużej maszynie. Próg wejścia jest naprawdę niewielki. W drugą stronę zadziała to tak samo - eksperiencja z przygód z Maliną przyda się do pracy z innymi, poważniejszymi platformami bazującymi na Linux, czy Unix. Do kompletu dochodzi ogromna ilość literatury, na wszelkie możliwe okazje, od administracji po development aplikacji sieciowych, jest w czym wybierać.

Awatar użytkownika
wojtek
Geek
Geek
Posty: 1901
Rejestracja: piątek 04 wrz 2015, 09:03
Lokalizacja: JO90JK

Re: [RETRO] Bezprzewodowy interfejs SCPI do Meratronik V543

Postautor: wojtek » niedziela 20 maja 2018, 06:53

Ja jestem, jak zwykle, pod wrażeniem pomysłu i włożonej pracy oraz osiągniętego efektu - brawo :D
73 Wojtek

tasza
Expert
Expert
Posty: 861
Rejestracja: czwartek 12 sty 2017, 10:24

[RETRO] Meratronik V543 vs WWW z Pythonem w tle

Postautor: tasza » sobota 26 maja 2018, 00:29

#slowanawiatr

♬ ☘ Moja muzyka do kodowania ♬ ♬ ♬ ☘
https://youtu.be/ItRgLtqw51s
♫ ♩ ♪ Blanc Faces ⚡ ☘ ⚡ Fly z albumu `Falling From The Moon` ♪ ♩ ♫


Dobór nut do postów nie jest u mnie przypadkowy, a teraz akurat miałam z tym pewien problem. Temat sieciowego SCPI stał się rozwojowy, a grupa Find Me, która towarzyszy tu Meratronikowi V543 nagrała wprawdzie świetne albumy, ale tylko dwa. Okazało się natomiast, że pan Robbie La Blanc, który udziela się tam wokalnie, jest też zaangażowany w projekt Blanc Faces. I to odkrycie pozwoli wątkowi pozostać w melodycznych klimatach AOR.
-- ❦ --
Pisanka poniżej to praktycznie w całości spontaniczna deweloperka, z łapą w usztywniaczu trudno mi cokolwiek więcej teraz majstrować. Temat prezentacji danych z urządzeń na stronie www był poruszony na forum, chcę więc teraz pokazać nieco inne podejście do tego zagadnienia, ale na zasadzie raczej alternatywy niż zawoalowanej konkurencji. Moje realia są zwyczajnie inne, postrzeganie zagadnień tego typu integracji sprzętu i oprogramowania także. Podstawowym obwarowaniem jakie przyjęłam na potrzeby tego testu to całkowita darmowość i ogólna dostępność wszelakich narzędzi, po drugie - fizyczna przenoszalność poszczególnych komponentów rozwiązania. W szczególności całą przedstawioną poniżej zabawkę można sobie uruchomić bez Meratronika i Raspberry PI, na zwykłym PC. No to lecimy.


Gotyckie łuczki i fasada z gipsu.

Z architekturą systemów informatycznych jest czasem tak, że to kilka pudełek połączonych kreskami, to niby komponenty i ich interfejsy i gotowe, a już niech się programiści dalej głowią jak to ugryźć. Sama występuje częstokroć po obu stronach tej barykady (jako arch i jako dev) stąd i dystans mam pewien do takich wysokopoziomowych oglądów na systemy IT, ale też świadomość jak bardzo takie rozplanowanie komponentów potrafi się przydać na wszelkich etapach pracy projektowej, choćby najprostszej, że o utrzymaniu późniejszym nie wspomnę. Spójrzmy zatem na to, co mamy poniżej:

Obrazek

W ujęciu UML to diagram komponentów, bardzo prosty wprawdzie, ale dość dobrze prezentujący składniki naszego mini-systemiku. Centralna cześć to dwa moduły programowe - konektor SCPI oraz serwer www, wszystko to osadzone w fizycznych realiach komputerka Raspberry PI. Z postu powyżej wiadomo jak działa interface do SCPI, tu materializuje się on w postaci aplikacji v543. Skoro mamy mieć interfejs webowy to oczywistą staje się konieczność dostawienia serwera www, stąd obecność aplikacji meraHttpServer. Serwer www komunikuje się z konektorem SCPI przez proste ramki tekstowe, egzotycznym dla świata protokołem, obrobione dane udostępnia w postaci stron HTML. I w sumie tyle z lotu ptaka. Aha, do serwera www klientów może się zapiąć tylu, na ile pozwoli jego wydajność, teoretycznie jest możliwe wykorzystanie przez klienta natywnego interfejsu SCPI w sposób bezpośredni, ale tego póki co nie chcemy.

UML - kto, z kim i kiedy

Samo działanie komunikacji klient-serwer (a w naszym przypadku przeglądarka-serwer www) prezentuje poniższy diagram sekwencji z miarę zgodny z notacją UML:

Obrazek

Wywołanie URI '/info' powoduje odesłanie do przeglądarki strony w HTML zawierającej podstawowe informacje o bieżącym stanie miernika, dane te są pozyskiwane przez serwer z sekwencji wywołań SCPI na programie komunikującym się z miernikiem. Oczywiście zauważamy, że powyższe to typowe wywołanie synchroniczne, trwa tyle ile sekwencja wywołań składowych plus czas potrzebny na zbudowani treści strony.

Komunikacja multimetru z aplikacją v543 była nieco trudna do narysowania na diagramie sekwencji, ponieważ tak naprawdę to Meratronik inicjuje ten proces zgłaszając przerwanie, dalsza komunikacja po SPI to jego konsekwencja. Dla uproszczenia przyjęłam wielką kropę czyli 'found message', to takie jakby zdarzenie, dalej już zachodzi klasyczna sekwencja request-response. Ważne w tym natomiast jest to, że aplikacja v543 otrzymawszy zapytanie via TCP/IP zwraca wartości zapamiętane od czasu ostatniego przerwania na LINE_READY, nie jest to stan bieżący w literalnym rozumieniu. Taka optymalizacja jest ceną za szybkość pracy interfejsu i jego wielodostępność. Zmienne z cache można swobodnie odczytywać bez potrzeby blokowania rywalizujących ze sobą połączeń klienckich.

Kolejny rysunek to diagram sekwencji dla wywołania URI '/meter' które to powoduje odesłanie stronki www ze stylizowanym w analogowych klimatach malunkiem miernika.

Obrazek

Tu sprawa wygląda nieco inaczej, ponieważ część akcji rozgrywa się po stronie serwera, a spora część po stronie klienta, w środowisku przeglądarki. Serwer ładuje z lokalnych zasobów treść html wraz z kodem javascript i odsyła do klienta. Uruchomiony kod javascript rysuje skalę analogowego miernika, a następnie periodycznie tworzy typowe wywołanie AJAX, którym pobiera z serwera bieżącą wartość mierzoną przez urządzenie. Zauważmy - strona ładowana jest tylko raz i nie ma potrzeby odświeżania jej zawartości. Cykliczne wywołania AJAX zapewniają zmianę treści w oczekiwanym przez nas zakresie, tu - kontrolują położenie wskazówki.

Anatomia prostego serwera www

Wspominałam, że będzie męczony Python i jestem konsekwentna - aplikacja meraHttpServer została sklecona w Python 2.7 (ponieważ taki jest preinstalowany w PI). Komplet to w sumie trzy pliki:

:arrow: https://github.com/bienata/piv543http/b ... pServer.py - serwerek sam w sobie
:arrow: https://github.com/bienata/piv543http/b ... /info.html - statyczna stronka z info o mierniku
:arrow: https://github.com/bienata/piv543http/b ... meter.html - stronka ze skryptem do analogowej skali

Pliki html to de facto zasoby udostępniane przez serwer, wyniosłam je na zewnątrz z uwagi na łatwość modyfikacji bez konieczności restartu aplikacji. Można oczywiście wbić kod html na stałe w jakieś const-stringi na poziomie aplikacji, ale wtenczas tracimy możliwość komfortowej zmiany treści niejako w locie. Serwer obsługuje metodę GET protokołu HTTP, z reguły zwracając `200 OK` i żądaną w URI treść.

/info

Zerknijmy dokładniej na fragment treści pliku info.html:

info.html pisze:

Kod: Zaznacz cały

<tr>
   <td nowrap align="left">&nbsp;*idn?</td>
   <td nowrap align="right"><b>$IDN$&nbsp;</td>           
</tr>


Jak widać w html wplecione są symbole-tagi typu $IDN$ i podobne, one są podmieniane na konkretne wartości podczas budowania treści po stronie serwera, robi to funkcja processInfoPage()

merahttpServer.py pisze:

Kod: Zaznacz cały

def processInfoPage( p ):
   p = p.replace( "$IDN$",    scpiCall( "*idn?"         ) )
   p = p.replace( "$MODE$",    scpiCall( ":meter:mode?"   ) )      
   p = p.replace( "$RANGE$",    scpiCall( ":meter:v:range?"   ) )   
   p = p.replace( "$DISPLAY$", scpiCall( ":meter:display?"   ) )   
   return p


Fizyczny kontakt z konektorem SCPI Meratronika zapewnia funkcyjka scpiCall(), cała seria jej wywołań pozwala pozyskać komplet danych potrzebnych do przygotowania zawartości strony.

merahttpServer.py pisze:

Kod: Zaznacz cały

def scpiCall( cmd ):
   s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
   s.connect( ("neonowy", 5555) )
   s.sendall( cmd.encode() )
   resp = s.recv( 1024 )
   s.close()
   return resp.decode().strip()   


Dodatkowo obsługa /info dokonuje prostego pomiaru czasu budowania strony, w sumie to byłam ciekawa jak szybko na takiej małej Malince będzie ten mechanizm pracował i nie ukrywam zaskoczenie było pozytywne - wychodziły niewielkie dziesiątki milisekund, przykład poniżej:

Obrazek

W formie objaśnienia:
"(pi) neonowy - Konsola" - to ssh, w niej uruchomiony Python z meraHttpServer.py
"(pi) neonowy - Konsola<2>" - to ssh, w niej uruchomiony proces v543 do komunikacji z Meratronikiem
Konsola <3> to poszukiwanie id procesu serwerka do dalszych testów

/meter

Teraz przechodzimy do analogowej części webowego interfejsu - wywołanie URI /meter.
Tu jest ciekawiej, ponieważ plik meter.html to zawartością dość prosty html, ale za to ze sporym kawałkiem javascript wewnątrz, do rysowania skali. Bibliotek do rysowania figur w przeglądarce jest cała masa, mnie w oko wpadły dwie: :arrow: http://dmitrybaranovskiy.github.io/raphael/ oraz :arrow: http://fabricjs.com/ I jakoś tak w Fabric poczułam się deko swobodniej, zatem skalę mierniczka pracowicie wydziubałam przy pomocy tejże. Oprogramowanie rysowania frontu nie było jakoś mega skomplikowane, ale przyznaje, w kilku miejscach kod mi się narowił, choćby podczas ustawiania pod kątem opisów podziałek skali. Możliwe, że takie pamiątkowe zrzutki ekranu wydadzą się zabawne, mi tam do śmiechu wtedy nie było:
http://bienata.waw.pl/microgeek/v543pc/err_scale_1.png
http://bienata.waw.pl/microgeek/v543pc/err_scale_2.png
http://bienata.waw.pl/microgeek/v543pc/err_scale_3.png

No i oczywiście eksperymenty z samym układem skali, chwilami holujące w kierunku pokracznego zegarka:

https://youtu.be/Qz0VM-AQ47s

Rysowanie unipolarnej skali to jedno, ale napędzana AJAX-em wskazówka chyba warta jest wzmianki, zatem:

meter.html pisze:

Kod: Zaznacz cały

function checkPointerPosition() { 
   var httpRequest = new XMLHttpRequest();           
    httpRequest.onreadystatechange = function() {       
       if (this.readyState == 4 && this.status == 200) {
          var meterNum = this.responseText;
           meterNum = Math.abs( meterNum / 100 );
           document.getElementById("rawMeterData").innerHTML = meterNum;
           needleAngle = 150-meterNum;
           canvas.remove( needle );                       
             needle = GetNeedle( needleAngle );
           canvas.add( needle );
           document.getElementById("counter").innerHTML = counter++;
       }
    };               
    httpRequest.open( "GET", meterUrl, true );           
    httpRequest.send();   
}


Widać od razu, że wywołanie open(..,..,true) na XMLHttpRequest jest asynchroniczne, to znaczy przeglądarka nie czeka na nadejście odpowiedzi z serwera tylko dalej kontynuuje pracę. Strona webowa jest dzięki temu responsywna, a odpowiedź z serwera zostanie uwzględniona, gdy tylko się pojawi (status:200, readyState:4). Druga zaleta z tej sztuczki taka, że generowany ruch z serwerem ogranicza się jedynie do niezbędnego zakresu potrzebnych akurat danych - nie przeładowujemy całej strony tylko po to, aby odmalować w nowym położeniu zwykłą wskazówkę.

Cykliczność wywołań AJAX zapewnia podłożenie naszej funkcji do setInterval() z zadanym parametrem czasowym:

meter.html pisze:

Kod: Zaznacz cały

setInterval( checkPointerPosition, 500 );         


Oczywiście, po stronie serwera wywołanie musi być obsłużone, zapewnia to kod skojarzony z URI '/meterData'.

Stronka z miernikiem analogowym wygląda następująco:

Obrazek

Obrazek

Opis okienek jak poprzednio.

Obrazek

Obrazek

Life on Top

Taki serial kiedyś był, sympatyczny nawet, a równie sympatyczne wydaje się proste narzędzie do monitorowania procesów systemu o nazwie top. Uruchomione ot tak sobie wyświetli stan prawie wszystkiego co żyje w systemie, informacji jest stanowczo zbyt wiele no i dynamicznie się zmieniają, procesy najbardziej obciążające CPU są właśnie na topie. Do obserwacji jak konektor v543 i serwerek meraHttpServer wpływają na zużycie mocy obliczeniowej wykorzystamy top, ale wywołany tak:

Kod: Zaznacz cały

top -pNNN,MMM

gdzie NNN, MMM to identyfikatoy (`pid-y`) interesujących nas procesów. Pozyskać je łatwo wywołując dla odmiany polecenie

Kod: Zaznacz cały

ps -Af

i traktując jego standardowe wyjście ogólnie lubianym grep-em.

Obrazek

Opcja f zapewni prezentację pełnego wywołania, które uruchomiło proces, a więc np. interpreter Python wraz z nazwą skryptu, opcja A pokaże procesy nie tylko z bieżącej sesji ssh, ale wszystkie, z innych terminal także.

Obrazek

Obrazek

Mając PID konektora i serwera www możemy pooglądać sobie jak pracują w naturalnym środowisku, nękane przez namolne kliknięcia w okno przeglądarki:

Obrazek

https://youtu.be/VhcmRQ9d0e0

Gdy Meratronika brak

To było nie rozbierać na zegarek, o! A na poważnie, taka jak zaproponowałam dekompozycja całości na składniki umożliwia zastępowanie jednych elementów innymi, grunt to spełnić założenia poczynione przy projekcie interfejsu. I tak na przykład konektor v543 współpracujący z prawdziwym multimetrem możemy spokojnie zastąpić jego swoistym emulatorem - małą aplikacyjką rozumiejącą zdefiniowane komendy SCPI i odpowiadającą z góry ustalonymi wartościami. Przecież serwerowi meraHttpServer jest wszystko jedno z kim rozmawia, póki tak dobrze się rozumieją, prawda?

Kod prostej udawaczki Meratronika znajduje się tu: :arrow: https://github.com/bienata/piv543http/b ... meraemu.py

Efekty pracy:

Obrazek

Obrazek

I na żywo:

https://youtu.be/SKx-Vs0MVno

Niezdrowa ciekawość

Ludzi wścibskich osobiście nie trawię, ale podsłuchanie jak rozmawiają ze sobą dwie aplikacje sieciowe wydaje się być interesującym zajęciem, tym bardziej że wszelkie narzędzia ku temu przydatne są w domyślnej instalacji malinowego Linuksa. Ot, wystarczy zdobyć PID emulatora i/lub serwera:

Obrazek

a następnie uruchomić polecenie strace wskazując wybrany do podsłuchiwania proces:

Kod: Zaznacz cały

strace -p 673 -f -e trace=network -s 10000


I wtenczas na konsoli dostaniemy:

Obrazek

Taki prosty trace sieciowy może pomóc nam w diagnostyce aplikacji lub ewentualnie inżynierii odwrotnej, gdy przykładowo musimy napisać własną aplikację-udawaczkę, chyba warto zapoznać się z tym sympatycznym programikiem.

-- ❦ --

tasza
Expert
Expert
Posty: 861
Rejestracja: czwartek 12 sty 2017, 10:24

Re: [RETRO] Bezprzewodowy interfejs SCPI do Meratronik V543

Postautor: tasza » sobota 26 maja 2018, 14:01

Z tym linuksem to może rzeczywiście przesadziłam, no to proszę - pod systemem Windows też jakoś działa. Tylko trzeba przestawić port serwera na inny niż 8080 bo się wykłada i dodać reguły inbound/outbound dla tcp/udp binarce python.exe, a najlepiej to w ogóle wyłączyć systemowy firewall i wszystko uruchamiać jako Administrator.

Obrazek
Obrazek

https://youtu.be/Bn1wMqbdexQ


Wróć do „Przyrządy pomiarowe”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 1 gość