SerialPort i nasłuchiwanie w C#

W poprzedniej notce zaprezentowałem prosty emulator Modbus, który niedawno napisałem. W tej notce postaram się napisać w jaki sposób zaimplementowałem obsługę portu szeregowego COM oraz nasłuchiwanie nieblokujące aplikację.

Zaczynając od początku, SerialPort jest klasą z .NET Framework, która umożliwia obsługę portów szeregowych. Na początek przykład, w jaki sposób pobrać listę dostępnych w komputerze portów:

string[] ports = SerialPort.GetPortNames();

I tyle, tablica stringów zawiera nazwy dostępnych portów. Ważniejszym krokiem jest ustanowienie połączenia (tu przykładowe dane):

SerialPort sp = new SerialPort();
sp.ReadTimeout = 1000;
sp.WriteTimeout = 1000;
sp.PortName = "COM1"	// Jeden z wylistowanych portów
sp.BaudRate = 115200;
sp.DataBits = 8
sp.Parity = Parity.None;
sp.StopBits = StopBits.One
sp.Encoding = Encoding.BigEndianUnicode;
 
try
{
    sp.Open();
}
catch (Exception err)
{
    /* ... */
}

Skoro port został otwarty można już coś do niego wysłać:

byte[] data = /* jakieś dane */
sp.Write(data, 0, data.Length);

Odbieranie danych wygląda analogicznie:

byte[] data = null;
if (sp.BytesToRead > 0)
{
    data = new byte[sp.BytesToRead];
    sp.Read(data, 0, data.Length);
}

Troszkę większym problemem jest sprawienie, by aplikacja oczekiwała na nowe dane, a w razie czego je obsłużyła, nie powodując jednocześnie zastoju. Do tego celu należy użyć wątków, a dokładniej jednego, w którym należy wywołać taką funkcję:

private boolean bReceiving = false;
 
public void Receive()
{
    byte[] data;
    while (bReceiving)
    {
        if (sp.BytesToRead > 0)
        {
            data = new byte[sp.BytesToRead];
            sp.Read(data, 0, data.Length);
            receiveHandler.DataReceivedEvent(data);
        }
 
        Thread.Sleep(50); // Żeby nie zużywać niepotrzebnie zasobów
    }
}

Funkcja ta, jak widać zawiera pętle, która sprawdza czy istnieją dane do odczytu, jeśli tak to je odczytuje i przekazuje dalej do metody, która z nich skorzysta. Kod wywołania wątku oraz interfejs receiveHandler jest następujący:

interface IDataReceiveListener
{
    void DataReceivedEvent(byte[] data);
}
 
Thread transmissionThread = null;
 
void Run()
{
    bReceiving = true;
    transmissionThread = new Thread(() => { Receive(); });
    transmissionThread.Start();
}

Teraz najważniejsze, ponieważ korzystam w tym kodzie z dwóch wątków (głównego + dodatkowego), w tym miejscu należy zwrócić szczególną uwagę na dostęp do danych prze oba wątki. W mojej aplikacji założyłem, że drugi wątek obsługuje obiekt SerialPort (mimo że tworzę go w pierwszym wątku), zatem dostęp do tego obiektu z wątku głównego (tutaj w przypadku wysyłania) musi być opatrzony sekcją krytyczną:

Thread.BeginCriticalRegion();
 
sp.Write(data, 0, data.Length);
 
Thread.EndCriticalRegion();

Natomiast jest jeszcze przypadek gdy wątek drugi odbiera dane i odwołuje się do obiektów z wątku pierwszego. W tym przypadku należy skorzystać funkcji Invoke() klasy Form, która przyjmuje obiekt typu delegate, a jego zadaniem jest wywołanie odpowiedniej funkcji z wątku pierwszego. Kod który to robi jest następujący:

private delegate void ProcessRequestDelegate(byte[] data);
 
/* funkcja interfejsu IDataReceiveListener */
public void DataReceivedEvent(byte[] data)
{
    this.Invoke(new ProcessRequestDelegate(this.ProcessRequest), new object[] { data });
}
 
private void ProcessRequest(byte[] data)
{
    // some stuff
}

I to wszystko na ten temat. Jak widać pisanie aplikacji okienkowych w C# jest banalnie proste.

Modbus Emulator

modbusEmulatorJednym z ostatnich zadań na laboratorium Informatycznych Systemów Sterowania (i jednocześnie jedynym ciekawym) było zaimplementowanie protokołu Modbus w postaci aplikacji emulujących urządzenia master i slave, komunikujących się ze sobą bezpośrednio korzystając z portów szeregowych COM (RS-232). Zadanie to zrealizowałem minimalistycznie tworząc jedną aplikację, która emuluje oba urządzenia i implementuje 6 pierwszych publicznych funkcji wraz z podglądem rejestrów.

Aplikacja jest napisana w C# i korzysta z Windows Forms oraz klasy SerialPort (która załatwia całą komunikację po porcie COM). Całość implementacji bazuje na specyfikacji Modbusa znajdującej się tutaj. Oprócz tego podczas pisania wykorzystywałem również kilka aplikacji:

Dwie ostatnie aplikacje posłużyły mi jako referencja implementacji protokołu, ponieważ sama specyfikacja nie zawiera informacji o sposobie liczenia CRC i LRC, więc trzeba było do tego dojść metodą prób, błędów i Google.

Sam program obsługuje (jak już wcześniej wspomniałem) 6 pierwszych, publicznych funkcji protokołu Modbus dla obu urządzeń (Master i Slave) przesyłając dane w trybie ASCII lub RTU. Urządzenie Slave posiada podgląd rejestrów Coils, Discrete Inputs, Input Registers oraz Holding Registers, po 4096 sztuk każdy (wszystkie Read-Only, generowane na podstawie seed = 0). Aplikacja posiada również podgląd wysyłanych i otrzymywanych ramek w postaci logu transmisji.

Program wraz z kodem źródłowym znajdują się tutaj (wymaga .NET Framework 2.0) .

SDKMeshInfo

Pisząc różne efekty graficzne, w pewnym momencie możemy stwierdzić, że potrzebujemy jakiegoś innego modelu. Wtedy nasuwa się również pytanie “skąd wziąć taki model?”. Tutaj przychodzi z pomocą DirectX SDK, które posiada dużą ilość różnych modeli w formacie .x oraz .sdkmesh. Z formatem .x można sobie poradzić funkcją

D3DXLoadMeshFormX

Funkcja ta wczytuje i parsuje model, zwracając wskaźnik, z którego można już korzystać.

SDKMeshInfoNiestety format .x jest bardzo prosty, ponieważ zawiera on tylko jeden zestaw materiałów i teksturę diffuse na subset. Problem ten rozwiązano tworząc nowy format z rozszerzeniem .sdkmesh. Powstał on i jest wykorzystywany na potrzeby przykładów Direct3D 10. Pliki tego formatu mogą zawierać kilka modeli, podzielonych na kilka subsetów. Materiały zostały rozszerzone o tekstury normal i specular. Dodane zostały również informacje o klatkach animacji, natomiast szczegóły danej klatki zawiera osobny plik z rozszerzeniem .sdkmesh_anim. Więcej szczegółów dotyczących tego formatu znajduje się w dokumentacji pod hasłem “Overview of the SDK Mesh File Format”.

Postanowiłem się zainteresować tym formatem nie tylko z powodu tego, że część modeli jest w nim zapisana, ale potrzebowałem modeli, które mógłbym wykorzystać do mojej zabawy z animacją opartą na klatkach kluczowych. Właśnie z tego powodu napisałem aplikację, którą tu zamieszczam. SDKMeshInfo jest programem do podglądu bebechów plików .sdkmesh. Nie posiada on opcji ich wyświetlania, ale pokazuje pełne dane z nagłówków zawartych we wskazanym pliku.

Download

NViDo v0.3 Release

Tym razem chciałbym przedstawić mój nowy program. NViDo jest to aplikacja do pobierania filmów z serwisów takich jak Youtube. Zaletą programu jest prostota obsługi, która może sprowadzić się do skopiowania linku do schowka i wciśnięciu skrótu klawiszowego “SHIFT + ALT + D”. Innymi funkcjami aplikacji są:

  • NViDoodtworzenie filmu zaraz po ściągnięciu
  • tworzenie historii pobranych plików wideo (z której można bezpośrednio odpalić dany plik)
  • pobieranie również wersji HD jeżeli istnieje w serwisie

Aktualnie ilość serwisów, które NViDo obsługuje nie jest szałowa, ponieważ są to tylko (już wspomniany) Youtube i Vimeo (w przyszłości pewnie dodam więcej). Aplikacja jest w miarę odbugowana, jeśli wystąpią jakieś błędy to postaram się naprawić (choć nie obiecuję).

Pobierz

W tym miejscu chciałbym zareklamować również inną aplikację tego typu, a mianowicie jDownloader. Ten program, oprócz tego, że automatycznie pobiera pliki z takich serwisów jak rapidshare, potrafi ściągać filmy z większości znanych serwisów podobnych do Youtube.

jDownloader

NLib

Postanowiłem udostępnić moją “bibliotekę”, którą posługuję się od jakiegoś czasu. Nie jest ona jakoś super wypasiona, ale zawiera wszystkie elementy, które są mi aktualnie potrzebne, czyli:

  • Moduł podstawowy – konwersje, typedefy, jakieś funkcje liczące w czasie kompilacji
  • Profile
  • Logger
  • FStream – strumień dla plików w oparciu o funkcje WinApi
  • StructReader – funkcja do obsługi bardzo prostych plików konfiguracyjnych
  • Timer – obsługa zegara, licznik FPS w oparciu o QPC lub GetTickCount()
  • Window – prosta klasa do obsługi okna

Update’y pojawiają się wraz z pomysłami i zapotrzebowaniem na nowe wynalazki, więc nie wiem kiedy nowa wersja.

Pobierz

Małe programy

Postanowiłem udostępnić dwie pomocne aplikacje, które były mi potrzebne kiedyś, więc sobie je na szybko skodziłem w ramach treningu. Oto one:

  • FileListing – aplikacja zapisuje ponumerowaną listę plików w katalogu, w którym została uruchomiona
  • NewLineFix -aplikacja naprawia wszystkie znaki nowej linii dodając do nich \r, przydatna przy czytaniu plików pisanych pod linuksem.

Mam nadzieję, że komuś się przydadzą :).

SSE i SSE 2 w Visual 2008

Przeglądając opcje projektu w Visual C++ 2008 Express Edition natrafiłem na opcję, która umożliwia kompilatorowi użycie dodatkowych instrukcji procesora z zestawów SSE i SSE2. Niestety nie wiem, które co i jak kompilator może zoptymalizować, ale myślę, że warto ustawić tę opcję na minimum SSE. A nuż coś pomoże. Aby uaktywnić tę opcję należy wejść do opcji projektu -> C++ -> Code Generation -> Enable Enhanced Instruction Set.

Próba uruchomienia programu zoptymalizowanego pod instrukcje wyższego zestawu po prostu się nie powiedzie, ale w dzisiejszych czasach kiedy dostępny jest zestaw instrukcji SSE3, można sobie pozwolić na minimum SSE.

FTPUploader

Jak zwykle następny post powstał po dłuższej przerwie, ale muszę przyznać czasem mi się nie chce, a czasem po prostu nie mam czasu. Tak też było tym razem, brak czasu spowodowany był szkołą (tak 3 klasa LO zobowiązuje), ale udało się znaleźć w niej czas na drobne projektowanie, a poza nią na kodzenie (taak, to jest nałóg). W wyniku tego kodzenia udało mi się spłodzić program o nazwie właśnie FTPUploader. Szczególne podziękowania należą się Krystianowi Dużyńskiemu “KrystianD”, za pomoc w chwilach mojej niewiedzy oraz kod, który był mi potrzebny do realizacji założeń. No ale do rzeczy (ReadME):

FTPUploader jest to prosty program potrafiący wysłać plik na wskazany serwer
za pomocą 2 kombinacji klawiszy.
Aby rozpocząć korzystanie z programu należy dodać do bazy danych żądane serwery
FTP, przy czym w polu Adres download należy podać ścieżkę, która będzie dodawana
do adresu pliku (w przypadku republiki na koncie o loginie zgred będzie to
zgred.republika.pl). Wysłać plik można na 2 sposoby:

Standardowy – naciskasz “Wybierz plik”, wybierasz plik, a na końcu “Wyślij”.
po wysłaniu plik automatycznie skopiuje się do schowka, jeżeli przypadkiem
zmienisz wpis w schowku możesz nacisnąć pole “Ostatni link” co spowoduje
ponowne wpisanie linku do schowka.

Hotkey’s – ta metoda jest dużo lepsze, zwłaszcza dlatego, że program działa w tle.
Aby wysłać plik tą metodą wystarczy po prostu skopiować plik do schowka
(kombinacja klawiszy Ctrl + C), a następnie wysłać plik wciskając klawisze
Shift + Alt + S, po wysłaniu link do pliku znajdzie się w schowku.
Kombinacja klawiszy Shift + Alt + L powoduje wpisanie do schowka ostatniego
linka. (Uwaga kombinacja klawiszy powoduje zmiane klawiatury w Viście,
proponuje zostawić sobie tylko klawiaturę polską.)

Program posiada bazę linków, w której znajduje się 20 ostatnich linków.

FTPUploader

Pobierz

A na koniec pragnę życzyć wszystkim zdrowych, wesołych i owocnych Świąt.

Mój pierwszy program w C#

Wczoraj napisałem, mojego pierwszego tool’a w c#, program jest mi potrzebny do podziału scenerii z RPGcore. Sposób działania jest następujący:

1. Podaje się kod odpowiedzialny za wyświetlanie elementów otoczenia na mapie, kod ten z pliku scenery.dat w folderze z mapą wygląda nastepująco.

[skala] 4×2
22:22
24:22

Odpowiada to wyświetleniu na mapie o współrzędnych 22:22 i 24:22 obrazka skały o wymiarach 4×2 (w kostkach po 25×25 pikseli). Problem polega na tym, że gra korzysta z kratki w punkcie 22:22 (przykładowo) i wyświetla całą skałę która odpowiednio wychodzi na pozostałe kratki (np. 23:22 i 22:23). Problem polega na tym, że jeżeli zniknie nam z mapy punkt 22:22 to zniknie nam cała skała która powinna być jeszcze wyświetlana w punkcie 25:22. Rozwiązanie polega na tym, aby podzielić skałę na części 1×1 czyli kostki 25×25 pikseli. Sam plik nie jest tutaj problemem, ale musimy jeszcze zmienić zawartość pliku scenery.dat aby wyświetlała całą skałę. I tu z pomocą przychodzi właśnie to oto narzędzie, wystarczy wkleić kod odpowiedzialny za pokazywanie całej skały 4×2 a otrzymamy kod, który wyświetli nam skałę w kawałkach.


minicalc_s

Oto link.

Wymagania: .NET framework 2.0