Kanał - ATNEL tech-forum
Wszystkie działy
Najnowsze wątki



Teraz jest 15 sie 2018, o 08:03


Strefa czasowa: UTC + 1





Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 7 ] 
Autor Wiadomość
PostNapisane: 21 lip 2018, o 18:02 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 11 mar 2014
Posty: 1386
Pomógł: 153

Obrazek

W ramach Mirkowego konkursu, dotyczącego API dla ATB-USBasp 4.2, powstał program SQP-I2Cscan :roll: napisany w C# z wykorzystaniem biblioteki "LibUsbDotNet C# USB Library", która jest do pobrania ze strony https://sourceforge.net/projects/libusbdotnet/.


Jest to mały i prosty program - jak chodzi o główną funkcjonalność skanowania I2C, to tylko kilkanaście linijek :). Znaczna część kodu to GUI z dodatkami, które powstawały, bo Mirek przeciągał termin zakończenia konkursu ;). Zasadniczo realizuje on tylko jedną praktyczną funkcję - skanuje magistralę I2C wykorzystując ATB-USBasp 4.2. Dla uprzyjemnienia korzystania, program realizuje autodetekcję podłączenia / odłączenia ATB-USBasp oraz graficznie prezentuje postęp oraz wyniki skanowania. Dodatkowo poprzez dostępny suwak można regulować prędkość magistrali I2C.
Wynik skanowania I2C prezentowany jest w tabeli podając adresy znalezionych urządzeń w formacie dziesiętnym i szesnastkowym oraz w konwencjach adresów 7-bitowego i 8-bitowego. Dodatkowo dodawana jest informacja o możliwych typach układów posiadających wykryty adres. Informacja o możliwych urządzeniach pobierana jest z pliku i2c_table.txt, dzięki czemu istnieje możliwość samodzielnej definicji nazw układów prezentowanych po ich wykryciu.

Obrazek

Dzięki temu, że biblioteka LibUsbDotNet dostępna jest zarówno dla Windows jak i Linux, powstała możliwość stworzenia aplikacji poprawnie kompilującej się, bez jakichkolwiek przeróbek, zarówno pod Windows jak i pod Linux (wykorzystując środowisko Mono). Co ciekawe, to ten sam plik wykonywalny SQP-I2Cscan.exe można uruchomić pod Windows jak i pod Linux :) i nawet nie ma znaczenie gdzie go skompilujemy :D.

Cały kod udostępniam na licencja GNU GPL v. 3.0, czyli dostępny jest kod źródłowy z pełnymi prawami do samodzielnej modyfikacji i rozpowszechniania.
Kod programu znajduje się w wątku konkursowym https://forum.atnel.pl/topic20920.html#p209345.
Dla lubiących narzędzia do wersjonowania, to ostateczną wersję wrzuciłem też do publicznego repozytorium https://bitbucket.org/rskup/sqp-i2cscan/.

Skończy z marketingiem i przejdźmy do szczegółów programowania :)

Jako, że nie lubię korzystać kobyły Microsoftu, to do programowania w C# używam środowiska SharpDevelop. Dlatego nie będę opisywał szczegółów tworzenia programu w GUI aplikacji (bo te w środowisku od MS może trochę się różnić) a skupię się tylko kilka kluczowych punktach.
Podstawową rzeczą jest dodanie biblioteki LibUsbDotNet do naszego stworzonego projektu. W moim środowisku wystarczy wejść w menu Project (Projekt) i wybrać Manage Packages... (Zarządzanie Pakietami) i w nim wyszukać w liście proponowanych dodatkowych pakietów LibUsbDotNet, następnie kliknąć Add (Dodaj) i po chwili mamy dodaną tę biblioteką do naszego projektu :D

Niestety przy korzystaniu z biblioteki LibUsbDotNet pojawia się drobny problem. W bibliotece mamy kilka metod do obsługi urządzeń libusb i niestety nie działają one zamiennie jak to chyba teoretycznie miało być :(. Dla niektórych wersja driverów libusb poprawnie działa wywołanie części funkcji a dla innych działają inne :(.
Najprościej jest pod Linuxem, bo tam działają te zbliżone nazwami do natywnych funkcji libusb. Te same funkcje działają pod Windows, ale tylko gdy mamy drivery pobierane bezpośrednio z projektu libusb-win32. Ale już prawie ten sam driver (te same wersje dll-ek) w paczce z podpisem cyfrowym, czyli ten sam co instaluje mkAVRCalculator (driver ten ma dodany dodatkową bibliotekę dedykowaną dla Windows libusbK.dll) wymaga używania funkcji z grupy UsbRegistry. Więc będziemy czasami mieli w kodzie sprawdzenie jaki mamy system :(.

Dla ułatwienia i zwiększenia czytelności podefiniowałem sobie w programie kilka stałych:
- stałe z informacjami identyfikującymi ATB-USBasp
- nazwę pliku w którym przechowywane są opisy urządzeń I2C
- zakres adresów I2C do skanowania
- potrzebne komendy pochodzące z API ATB-USBasp
Składnia: [ Pobierz ] [ Ukryj ]
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.



No to zacznijmy coś konkretnego pokodować :D

Na samy początku program, w celu wykrycia czy podpięty jest do komputera ATB-USBasp, wywołujemy funkcję FindATBUSBaspDevice(), która to przegląda wszystkie urządzenia libusb i na podstawie VID i PID oraz nazwy i serial stringa ustala czy jest podpięte właściwe urządzenie. Niestety w Linux tą metodą nie jest zwracana nazwa i serial, więc one są tam nie weryfikowane. Czyli pod Windows wykrycie urządzenia jest z dokładnością do ATB-USBasp a pod Linuxem każda wersja USBasp zostanie uznana za prawidłową (oczywiście jest możliwość dokładnego kolejnego sprawdzenia czy to jest na pewno ATB-USBasp, ale ja już tego nie zrobiłem ;) ):
W przypadku wykrycia ATB-USBasp funkcja oprócz zwrócenia tego (poprzez wartość true), aktualizuje zmienną globalną MyUsbRegistry w której przechowujemy wskazanie na nasze urządzenie.
Czyli przy starcie programu wykonujemy:
Składnia: [ Pobierz ] [ Ukryj ]
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Zmienna bool ATBUSBasp przechowuje informację czy mamy podłączone ATB-USBasp, a funkcja SetATBUSBaspStatus() ustawia odpowiednio GUI i informacje prezentowane na nim. Funkcja FindATBUSBaspDevice() realizuje właściwe sprawdzenie istnienia urządzenia ATB-USBasp wygląda następująco:
Składnia: [ Pobierz ] [ Ukryj ]
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Ewentualne dalsze zmiany urządzeń libusb zrzucimy na karb zaimplementowanych w bibliotece procedur DeviceNotifier. Podpinamy naszą funkcję OnDeviceNotifyEvent(), by była wywoływana na zdarzeniach zmian stanów urządzeń:
Składnia: [ Pobierz ] [ Ukryj ]
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Nasz funkcja sprawdza czy zdarzenie dotyczy naszego VID, PID i czy jest typ zdarzenia nas interesujący (pojawienie się urządzenia => DeviceArrival oraz usunięcie urządzenia => DeviceRemoveComplete):
Składnia: [ Pobierz ] [ Ukryj ]
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Sprawdzanie w przypadku pojawienia się urządzenia, czy pracujemy pod Linuxem, spowodowane jest tym, że drugie wywołanie funkcji FindATBUSBaspDevice() w tym środowisku powoduje błędne informacje, więc pomijamy to i bazujemy tyko na VID i PID ze zdarzenia.

Mamy więc wykrywanie i informowanie użytkownika (poprzez modyfikacje GUI) o podpięciu lub usunięciu urządzenia ATB-USBasp. Pora więc zacząć się z nim komunikować :).
Jak to bywa przy komunikacji ze wszystkimi urządzeniami, to pierwszą funkcją jaką należy wykonać jest otwarcie urządzenia. Realizowane jest to, za każdym razem po wyzwoleniu skanowania I2C, poprzez funkcję OpenATBUSBaspDevice(), która przy okazji przypisuje nam identyfikator urządzenia do zmiennej globalnej MyUsbDevice.
Oczywiście tutaj także musimy użyć różnych funkcji dla Windows i Linux, bo wspominany wcześniej problem wersji sterowników ma tutaj znaczenie.
Składnia: [ Pobierz ] [ Ukryj ]
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Zamknięcie połączenia z urządzeniem (wykorzystywane po skończeniu skanowania urządzeń na I2C) realizowane jest w funkcji CloseATBUSBaspDevice():
Składnia: [ Pobierz ] [ Ukryj ]
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.



Po otwarciu urządzenia zostaje nam tylko zacząć wysyłać do niego komendy zgodnie z API.

Samo wysłanie danych do urządzenia realizujemy w programie poprzez funkcję SendToATBUSBaspDevice(), która korzysta z funkcji biblioteki MyUsbDevice.ControlTransfer(). API ATB-USBasp zwraca status wykonania większości komend poprzez zwrócenie stringa "OK" lub "ERROR". Sprawdzamy to, ale dla uproszczenia (bo po co porównywać ciągi ;)), patrzymy tylko na długość zwróconego ciągu :). Dzięki takiemu podejściu od razu dla komend które nic nie zwracają mamy także interpretację OK :D
Składnia: [ Pobierz ] [ Ukryj ]
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Do wywołania funkcji konieczne jest zdefiniowanie wartości zmiennych wejściowych (zgodnie z API ATB-USBasp), co jest banalne :D:
Ustawienie prędkości zegara SCL wygląda następująco:
Składnia: [ Pobierz ] [ Ukryj ]
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


A sprawdzenie obecności urządzenia na szynie I2C wygląda następująco:
Składnia: [ Pobierz ] [ Ukryj ]
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.



Teraz pozostaje złożyć części kodu w całość i dorzucić trochę iteracji z GUI, by użytkownik lubi jak się zmieniają różne rzeczy jak program działa a szczególnie jak coś klika ;)

Podsumowując, po kliknięciu przycisku skanowania I2C, gdy mamy podłączone ATB-USBasp, musimy otworzyć urządzenie (korzystając z funkcji OpenATBUSBaspDevice()), następnie ustawić wymaganą przez użytkownika prędkość dla I2C (poprzez funkcję i2cSetSCL()) i przystąpić do odpytywania kolejnych adresów (korzystając z funkcji i2cCheck()). Jeżeli funkcja zwróci prawdę, to znaczy że mamy urządzenie o takim adresie na szynie I2C, wtedy dodajemy informacje o tym urządzeniu do wyświetlanej tabelki i skanujemu kolejne adresy. Na koniec skanowania musimy zamknąć połączenie z urządzeniem i powiadomić użytkownika o zakończeniu działań.

Jak we wszystkich bibliotekach i poradnikach Mirka, także w API ATB-USBasp stosowany jest adres w notacji 8 bitowej (wartość łącznie z bitem R/W na najmłodszej pozycji), dlatego przy skanowaniu nie wysyłamy kolejnych wartości, tylko z przeskokiem co dwa.
Ale ja, na przekór :twisted: , lubię stosować notację 7-bitową, i taką używam w programie. Dlatego wartości zakresów adresów do skanowania zdefiniowane w stałych są 7 bitowe (I2C_7BIT_ADDRESS_MIN / I2C_7BIT_ADDRESS_MAX) a wartość wysyłana poprzez API jest przesunięta o jeden bit w lewo
Składnia: [ Pobierz ] [ Ukryj ]
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Zgodnie ze specyfikacją I2C, nie wszystkie adresy przeznaczone są dla normalnych urządzeń. Dlatego nie skanujemy całego zakresu a tylko jego część. Początek i koniec jest zdefiniowany we wspominanych wcześniej stałych I2C_7BIT_ADDRESS_MIN (najmniejszy adres) oraz I2C_7BIT_ADDRESS_MAX (największy adres).

Program posiada możliwość pokazywania w tabeli, oprócz adresów znalezionych urządzeń, także dodatkowych informacji o możliwym typie tego urządzenia. Realizowane jest po poprzez wczytanie takich informacji zaraz po uruchomieniu programu z pliku o nazwie zdefiniowanej w stałej programu I2C_DESCRIPTION_FILE (domyślnie jest to plik i2c_table.txt) do zdefiniowanej listy:
Składnia: [ Pobierz ] [ Ukryj ]
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Wczytanie pliku odbywa się poprzez funkcję readI2CDeviceDescriptionFile(). Gdy plik zostanie załadowany ustawiana jest zmienna I2CDescriptionInfo, która to informuje czy mamy skąd próbować podawać nazwę urządzenia po jego wykryciu na I2C.
Informacje w plik mogą być modyfikowane przez użytkowników, o ile zachowana zostanie jego struktura (w źródłach dołączony jest przykładowy drugi plik i2c_table_long.txt, zawierający więcej informacji o urządzeniach).

Skanowanie urządzeń na I2C jest bardzo szybkie. Stosowanie normalnego sterowania progress bar-a (paska postępu) powoduje, że gdy pojawia się już komunikat o zakończeniu skanowania to progress bar jeszcze jest w połowie i sobie powoli jeszcze cały czas rośnie. Spowodowane jest to stosowaniem animacji progress bara przez Windowsowy interfejs Aero. Niestety nie ma opcji wyłączającej tę animację :(. Aby animacja się nie wykonywała to wymagane jest zastosowanie triku przy wpisywaniu kolejnych wartości do progress bar-a (dlatego prograss bar sterowany nie jest bezpośrednio a poprzez dodaną funkcję SetProgressNoAnimation()).

Dziwne dodane wpisy na końcu w funkcji MainFormFormClosing() spowodowane są tym, że biblioteka LibUsbDotNet ma chyba jakieś błędy i pod Linuxem są problemy z zamykaniem programu - przy eleganckim zwalnianiem zasobów. A w ten sposób robimy to trochę mniej elegancko ;).

--
Pozdrawiam,
Robert



Ostatnio edytowano 22 lip 2018, o 10:46 przez rskup, łącznie edytowano 1 raz

Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 21 lip 2018, o 19:59 
Offline
Moderator
Avatar użytkownika

Dołączył(a): 03 paź 2011
Posty: 23354
Lokalizacja: Szczecin
Pomógł: 873

no jeszcze nie mam czasu na analizę - ale po prostu MIODNIE się na to patrzy ;) i aż chce się uczyć nowych rzeczy - brawo!

_________________
zapraszam na blog: http://www.mirekk36.blogspot.com (mój nick Skype: mirekk36 ) [ obejrzyj Kurs EAGLE ] [ mój kanał YT TV www.youtube.com/mirekk36 ]



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 21 lip 2018, o 20:11 
Offline
Użytkownik

Dołączył(a): 25 lip 2013
Posty: 1506
Pomógł: 73

Super projekt i tutorial!



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 22 lip 2018, o 10:56 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 11 mar 2014
Posty: 1386
Pomógł: 153

Uzupełniłem opis do końca :). Niestety trochę tego wyszło :shock: .

Na ewentualne pytania chętnie odpowiem.
Jako, że programy piszę tylko od przypadku, to mogą znaleźć się jakieś błędy lub przeoczenia :roll: . Dlatego śmiało zachęcam do komentowania (nawet tego krytycznego).


Na wspominany konkurs stworzyłem także wersję programu w C bez GUI - uruchamianego z wiersza poleceń i tekstowo wypisujący informacje wynikowe). Oczywiście tam także ten sam kod programu działa pod Windows i Linux. Jego kod jest znacznie prostszy i krótszy, więc jak będą chętni, to mogę go podobnie zaprezentować :).

--
Pozdrawiam,
Robert



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 22 lip 2018, o 14:37 
Offline
Użytkownik

Dołączył(a): 25 lip 2013
Posty: 1506
Pomógł: 73

Pewnie, że prezentuj. Zawsze można się czegoś nowego nauczyć :)



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 29 lip 2018, o 17:03 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 11 mar 2014
Posty: 1386
Pomógł: 153

micky napisał(a):
Pewnie, że prezentuj. Zawsze można się czegoś nowego nauczyć :)
To umieściłem jego opis w nowym wątku topic21056.html.

--
Pozdrawiam,
Robert



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 29 lip 2018, o 21:02 
Offline
Użytkownik

Dołączył(a): 25 lip 2013
Posty: 1506
Pomógł: 73

Great job!



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
Wyświetl posty nie starsze niż:  Sortuj wg  
Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 7 ] 

Strefa czasowa: UTC + 1


Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zidentyfikowanych użytkowników i 1 gość


Nie możesz rozpoczynać nowych wątków
Nie możesz odpowiadać w wątkach
Nie możesz edytować swoich postów
Nie możesz usuwać swoich postów
Nie możesz dodawać załączników

Szukaj:
Skocz do:  
Sitemap
Technologię dostarcza phpBB® Forum Software © phpBB Group phpBB3.PL
phpBB SEO