Linux, DosBox i /dev/ttyS0

Jak wiadomo - programista nie pracoholik - grać musi. Co należy jednak zrobić gdy jego sprzęt nie daje mu do końca takiej możliwości?

Wbrew pozorom, nie chodzi wcale o granie w super-wypasionego MMORPG’a - chodzi o grę starą i niemalże zapomnianą: The Settlers 2. Jaki więc mam problem skoro bóg zesłał programistów, którzy napisali DosBOX’a nawet na Linuksa?

Problemem jest gra na dwóch graczy. Każdy kto grał w The Settlers 2 wie o co chodzi - trzeba podłączyć 2 myszki, z czego co najmniej jedna musi być na porcie szeregowym (COM). Niby nic, ale co jeśli nie ma takiego portu? ^^ Np. ja w moim laptopie go nie mam i tutaj zaczynają się schody.

Poszperałem trochę w internecie i znalazłem informację, że porty szeregowe w linuksie reprezentowane są przez pliki /dev/ttyS* ( * - numer portu 0-3 [odpowiednio COM1-4] ). Istotne też, aby pamiętać, że ‘S’ ma być duże ;) Znalazłem taki port u siebie w katalogu /dev jednak nie mam pojęcia co mogę z tym zrobić dalej skoro nie mam takiego portu fizycznie? ^^

Napisałem nawet program który czyta dane z portu myszy ( /dev/input/mouse* ) i wysyła je na /dev/ttyS0 ale niestety sam DosBOX nie chce czytać tego portu zwracając przy starcie komunikat o błędzie:

Serial1: Opening /dev/ttyS0
tcgetattr failed with error 5.

Nie mam zielonego pojęcia co oznacza kod 5 bo nie mogłem znaleźć tego w internecie, ale pewnie ma to związek z brakiem fizycznego portu rs232 w moim laptopie.

Nasuwa mi się na myśl tylko jedna rzecz - jakiś wirtualny port szeregowy. Pytanie tylko czy to podziała… Może ktoś ma jakiś pomysł co do tego? Jestem otwarty na pomysły :)

Jak tymczasowo pozbyć się argumentu funkcji?

Dzisiaj wpadłem na pomysł jak można tymczasowo pozbyć się argumentu z funkcji, bez komentowania jej za pomocą /**/. Przykładowo, mamy wywołanie funkcji:

jakas_funkcja( argument1, argument2, argument3 );

Załóżmy, że argument drugi jest wskaźnikiem i chcemy go chwilowo ustawić na NULL bez usuwania samego argument2. Naturalnym byłoby zastosowanie komentarza, ale dzięki specyfikacji C++ można to zrobić jeszcze fajniej ^^

jakas_funkcja( argument1, (argument2,NULL), argument3 );

I o co w tym chodzi? :) Otóż kiedy program dotrze do drugiego parametru funkcji, natrafi na wyrażenie (argument2, NULL). Niezależnie od tego jaki by nie był argument2 wynik takiego wyrażenia jest zawsze wynikiem ostatniego “pod-wyrażenia” - czyli w tym wypadku NULL. Dlatego też do funkcji zostanie przekazana wartość NULL. Później jeśli już chcemy przywrócić argument2 do łask - wystarczy wywalić “,NULL” i można zostawić samo “(argument2)” bo ten nawias już i tak nic nie zmienia, a w przyszłości możemy go znów wykorzystać do tego samego celu ;)

Niby nic, a czasem przydatne - zwłaszcza jeśli argument2 jest wywołaniem jakiejś funkcji i chcemy aby się ona wykonała, ale chwilowo nie chcemy przekazywać wyniku tej funkcji do jakas_funkcja().

Wpadłem na ten pomysł właściwie przed chwilą, ale to głównie dzięki mojemu profesorowi prowadzącemu wykład z C, który zwrócił mi uwagę, na fakt, że wartością całego wyrażenia - jeśli mamy kilka przecinków - jest zawsze to po ostatnim przecinku.

Podsumowując - nawet z 8-letnim doświadczeniem z C++ warto chodzić na wykłady z C ;) (poza tym to świetna okazja, żeby sobie coś zakodzić przy okazji słuchając muzyki i od czasu do czasu wykładowcy ;P)

Programowanie Niskopoziomowe - MARIE

Na ostatnim wykładzie z systemów operacyjnych pojawiła się MARIE (Machine Architecture that is Really Intuitive and Easy). Bardzo przyjemnie słuchało się o tym, że programiści nie musieliby już przepinać kabli na wielkich ścianach aby dodać 2 liczby, jednak sposób programowania tej maszyny - na dzień dzisiejszy - daleko odbiega od jej nazwy. Głównym problemem jest tutaj część: “Intuitive and Easy”. Mam swoje zdanie na temat intuicyjności i prostoty programowania ;)

Tak czy inaczej. Nie udało się uniknąć starcia z Assemblerem MARIE. Po szybkim zapoznaniu się z nim od razu zauważyłem, że Assembler, którego używa się w dzisiejszych komputerach jest wręcz językiem wysokiego poziomu ;) Programowanie MARIE nie jest strasznie trudne, ale dość męczące. Tym bardziej, że na wykładzie dostaliśmy zadanie napisania programu sumującego n pierwszych wyrazów ciągu Fibonacciego.

Oczywiście na rozgrzewkę trzeba było napisać sobie kilka programów. Przykładowo program do dodawania dwóch liczb pobranych od użytkownika wygląda tak:

	Input
	Store 	TMP
	Input
	Add	TMP
	Halt
TMP,	DEC	0

Napisanie programu sumującego n pierwszych liczb ciągu Fibonacciego zajęło mi dobre kilka godzin, ze względu na to, że ciężko było się w nim połapać. Obowiązuje tu zasada: “Jeśli napisany kod nie działa jak należy, zamiast naprawiać - napisz go od nowa.”, którą oczywiście właśnie wymyśliłem.

Ogromnym utrudnieniem programowania tej maszyny jest fakt, ze nie daje się dodawać ani odejmować stałych bezpośrednio w kodzie. Trzeba je ręcznie zapisywać w kodzie. Przykładowy kod zwiększający N o 1:

	Load	N
	Add	ONE
	Store	N
	Halt
N,	DEC	0
ONE,	DEC	1

Nie ma także instrukcji do mnożenia więc programowanie czegoś bardziej złożonego jest raczej trudne ^^ Tak czy inaczej, muszę się przyznać, że podobała mi się ta zabawa w programowanie Undergroundowe ;)

Do While False [DWF]

Przemierzałem sobie bezkresne obszary www.gamedev.net i natrafiłem tam na fajny mechanizm o nazwie DWF. Wygląda to tak:

do {
	if( !doSth() ) break;
	if( !doSthElse() ) break;
	if( !doAnotherThing() ) break;
	doLastThing();
} while( false );

Na pierwszy rzut oka mechanizm bez sensu. Po co pętla skoro i tak wiadomo, że wykona się tylko raz?!

Po spojrzeniu drugi raz zaczyna to mieć sens. Dzięki takiemu mechanizmowi można uzależnić wykonywanie kolejnych operacji od wyniku poprzednich w prosty sposób. W innym wypadku trzeba by było pisać masę zagnieżdżonych if‘ów. Ten poprzedni przykład zadziała tak samo jak to:

if( doSth() )
{
   if( doSthElse() )
   {
      if( doAnotherThing() )
      {
         doLastThing();
      }
   }
}

Chyba nikogo nie muszę przekonywać, że poprzednie rozwiązanie było lepsze. To jest oczywiście najprostszy przykład, w którym różnica nie jest aż tak straszna, ale dla większej ilości instrukcji może to być problem.

Zwłaszcza jeżeli nie mamy funkcji takich jak doSth(), doSthElse() i wszystko wklepujemy do programu, wtedy takie zagnieżdżone if’y nie wyglądają zbyt ładnie :)