• Moving to Nokia Siemens Networks

    I decided to change company I work for few days ago. Today it's my first day I am working for Nokia Siemens Networks.

    I would like to kindly thank to everyone who worked with me during last years. I consider Gigaset AG as a place of competeness and cooperation. I wish my new employeer could offer me at least similar possibilities I met at Gigaset AG.
  • ACCU 2012 - Random thoughs

    I consider this post as a kind of small conclusions after ACCU 2012 conference in Oxford, UK I took part in.


    1. Python, range, and for-loop
    Those who are familiar with python syntax are not surprised with following listing:
    for i in range (10):
    print i
    It's python, so nothing interresting already happened. Here's the question: how can we achieve similar syntax in C++?
    I believe you agree with me that this is not possible in C (unless you use ninja pre-processor macros). C++2003 doesn't help too much here, even with template stuff. However, in C++11 (with origin library written by Andrew Sutton) it seems to be possible:
    for (const auto& i: bounded_range<int>(1, 10))
    {
    std::cout << i << std::endl;
    }
    When I saw presentation about origin library for the first time I though "WAT?!"[1]. After some time I started to realize how much C++11 will change capatibilities of C++ language at all. Now I wonder if following snippets could also be rewritten to C++11 with minimal syntax changes :-).
    for i, j in enumerate (alphabet): # alphabet = ['a', 'b', ..., 'z']
    print i, j
    for i in zip(range(1, 10), range(10, 20)):
    print i

    2. Funny fact about endl
    Interresting thing: if we dig enough deep into implementation of C++ STL, we are likely to find something like that:
    template<class charT, class traits>
    inline basic_ostream<charT, traits>& endl(basic_ostream<charT, traits>& os)
    {
    os.put(os.widen('\n'));
    os.flush();
    return os;
    }
    I'm aware that this isn't hitting performance and makes code less clear, but instead of:
    std::cout << "Hello, world!" << std::endl;
    you can actually write
    std::endl(std::cout << "Hello, world!");
    not to say that std::endl is generally slower than simple "\n";

    3. Designing APIs: two important rules
    Designing user-friendly, error-prone, easy, understandable, and eventually functional API is very hard task. But when you do, you must follow specific rules so final API is not a crap. Besides other rules I find these are also very important, but sometimes not followed:
    • do not mix abstraction level in your API
    • do not provide two functions which essentially perform the same work
    And now time comes for rationale. In the first case when you accidentally mix abstraction level, users of your library might end up with something similar to following.
    Scene scene;
    Object object;
    scene.AddObject(object);
    Renderer.Render(screen, scene);
    Renderer.PutPixel(0, 1, Color(255, 255, 0));
    Renderer.SwapFramebuffers();
    In above snippet we can easily see that Renderer class should perform high-level tasks related to rendering some sort of scene with objects. However, the API mix abstraction levels, so user is confused and starts using methods that manipulate on single pixels. After that, another method SwapFramebuffers is evaluated, but at this level it should have been hidden from the user. If the user wanted more control about what's displayed on the screen, he would access some lower layer instead of Renderer class, which is supposed to do the work without much effort spent on configuring things.

    Not following second rule may be even worse. Consider following example.
    Scene scene;
    ObjectManager objectManager;
    Object object;
    // Adding object to scene, case I
    scene.AddObject(object);
    // Adding object to scene, case II
    objectManager.pushObjectToScene(object, scene);
    // Rendering scene, case I
    Renderer.Render(screen, scene);
    // Rendering scene, case II
    scene.AssignScreen(screen);
    Renderer.Render(scene);
    Above snippet is quite confusing, isn't it? Basically, when you create a lot of paths in your API that lead to the same effect you can accidentally confuse library users. In effect instead of giving possibilities you make library less-understandable and less-convenient.


    I think that would be all I got for this time. Hope that helps you in any area.
  • Własny bootloader w AT&T

    Zaczęło się dosyć niewinnie - pewnego razu w celu sprawdzenia swojej pamięci RAM (coś nawalało) zaciągnąłem i odpaliłem program memtest86 na komputerze. Kiedy wykonywał on swoje testy zacząłem się zastanawiać w jaki sposób skonstruowany jest program typu bootloader. Całe te rozmyślania zaprowadziły mnie do szatańskiej idei napisania własnego bootloadera, czyli sprawdzenia tego po "kowbojsku".

    Od początku byłem przekonany, że nie wyjdzie z tego nic bogatego - raczej taka studencka bieda. Skupiłem się więc na najprostszym zadaniu, czyli wyświechtany "Hello, world!". Z drugiej strony mimo swojej prostoty pisanie takiego bootloadera może dużo nauczyć. W sieci znalazłem kilka stron opisujących tworzenie systemów operacyjnych od podstaw (np. tu lub tu), ale wszystkie one przykłady podane były w składni NASM. Nie obchodziło mnie za bardzo co jest lepsze... znalazłem pustkę w polskim internecie i zamierzałem ją wypełnić. Co prawda wspomniany memtest86 i jak się później okazało bootloader Minixa używały składni AT&T - ale na szczęście nie wiedziałem o tym, popsuło by mi to zabawę.

    Opis tego co się dzieje po uruchomieniu komputera znajdziecie na wymienionych stronach. Przydaje się również znienawidzony za czasów studiów, a doceniony po studiach using as. Bez tablicy przerwań BIOS też nie zbo(ot|j)ujemy za wiele, więc warto ją mieć pod ręką. Kończąc słowo wstępu, a zaczynając jednocześnie czyn, powstaje taki oto kod:
      1 .code16  
    2 _begin:
    3 .section .text
    4 .globl _start
    5
    6 _start:
    7 movw $0x07c0, %ax # Tutaj startujemy (BIOS).
    8 movw %ax, %ds # Ustawiamy stos (4K).
    9 movw %ax, %ss
    10
    11 movw $message, %si # Wkładamy wiadomość do rejestru.
    12 movb $0x0e, %ah
    13 movb $0x4f, %bh
    14
    15 _repeat:
    16 lodsb
    17 cmpb $0, %al
    18 je _loop
    19 int $0x10
    20 jmp _repeat
    21
    22 _loop:
    23 movb $0x07, %ah
    24 movb $0, %al
    25 jmp _loop #...
    26
    27 message:
    28 .byte 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13
    29 .byte 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13
    30 .ascii "Komputer zostal zablokowany\r\n"
    31 .byte 10, 13
    32 .ascii "Uzytkownik tego komputera odwiedzal zakazane przez prawo strony internetowe, na ktorych rozpowszechniane sa tresci nazistowskie. W celach prewencyjnych komputer zostal zablokowany, a identyfikator sprzetowy wyslany do jednostki EUROPOL Wroclaw.\r\n"
    33 .byte 10, 13
    34 .ascii "Jezeli uwazasz, ze komunikat pojawil sie na wskutek bledu, prosimy o kontakt z konsultantem pod numerem telefonu +48XXXYYYZZZ.\r\n"
    35 .byte 10, 13
    36 .byte 10, 13
    37 .byte 10, 13, 0
    38 message_len:
    39 .long . - message
    40
    41 .section .text
    42
    43 _end: # Dwa ostatnie bajty sektora MBR
    44 .org 510 # muszą być ustawione na 0xaa55.
    45 .byte 0xaa, 0x55
    46
    47
    Tak, też było mi ciężko w to uwierzyć - jak mogło wyjść tak krótko? Co tak właściwie się tutaj dzieje?

    Pierwszą rzeczą jaką należy zrobić po uruchomieniu to nastawić stos i inne niezbędne segmenty pamięci (7-10). W następnych liniach stać się może wszystko. Dosłownie wszystko. W moim prostym przypadku wyświetlam stringa na ekranie (11-14). W tym celu do rejestru si podaję adres wiadomości, a następnie wywołuję przerwanie BIOS numer 16 podając jako parametr 14 (górny bajt rejestru A). I to wszystko, w zasadzie. Na koniec uzupełniamy plik, aby kończył się dwoma bajtami 0xaa55 i zajmował łącznie 512 bajtów (rozmiar sektora uruchomieniowego).

    Kompilacja i stworzenie obrazu płyty jest nieco trudniejsza niż w przypadku NASMu, ale jak to mawiają ludzie ja tego nie zrobię?!. Z pewnością przyda się krótki plik Makefile, żeby za każdym razem nie trzeba było się zastanawiać jak się to budowało.

    Potrzebne nam będą pliki pomocnicze: ten oraz ten. Pierwszy z nich to obraz dyskietki floppy, a drugi to Makefile. Nie zostaje nic jak wpisać szatańskie polecenie `make` i czekać na obraz płyty. Płytkę można oczywiście sobie wypalić, aby się przekonać na własnych chipach, że wszystko huczy. Zanim jednak do tego dojdzie proponuję skonfigurować jakąś maszynę wirtualną i na niej przeprowadzać testy. Osobiście przetestowałem temat na netbooku. Oto co zobaczyłem po wypaleniu obrazu na zwykłą pamięć USB i odpowiednim przestawieniu BIOSa w komputerze:

    Image captured by a digital camera
    Dziękuję za uwagę.
  • [PL] SMS PDU - Format wiadomości w praktyce

    Popularne SMSy przesyłane mogą być w dwóch formatach: tekstowym lub PDU (ang. Protocol Data Unit). Z oczywistych przyczyn pierwszy wariant jest używany rzadziej. Możliwości, jakie mamy zaś w PDU są następujące.

    • 7 bity na znak - rozwiązanie pozwalające na uzyskanie max. 160 znaków na SMS,
    • 8 bity na znak - opcja pośrednia, 140 znaków,
    • 16 bitów na znak - czyli dla bogatych (70 znaków/SMS).
    Powyższe skomplikowane obliczenia uwzględniają nagłówek PDU, więc proszę mnie nie posądzać o nieumiejętność dzielenia :-). Format wspomnianego nagłowka jest całkiem nieźle opisany w tym miejscu.
    Koniec części teoretycznej. Odpalamy swój najlepszy edytor tekstowy (vim), zaprzągamy ulubiony język (python), i ... dewelopujemy na wesoło.
     1 #!/usr/bin/env python
    2 # -*- coding: utf-8 -*-
    3
    4 def int2hex (n):
    5 s = '%X'%n
    6 if int(len(s))%2 == 1:
    7 s = '0'+s
    8 return s
    9
    10 def encode_message (message):
    11 pdu = ""
    12 l = len (message)
    13 message += '\0'
    14
    15 # Wyznaczamy rozmiar tekstu po upakowaniu.
    16 msglen = int (len(message)*7/8)
    17
    18 # Inicjujemy bufor i zmienne.
    19 buf = [0] * msglen
    20 c = shift = 0
    21
    22 # Dla każdego septetu...
    23 for n in range(msglen):
    24 # Przeskok po każdej paczce 7 bajtów.
    25 if shift == 6:
    26 c += 1
    27
    28 # Wyznaczamy oktet z dwóch septetów.
    29 shift = n % 7
    30 lb = ord(message[c]) >> shift
    31 hb = (ord(message[c+1]) << (7-shift) & 255)
    32 buf[n] = lb+hb
    33
    34 c += 1
    35
    36 # Łączymy wiadomość z jej rozmiarem w postać heksadecymalną.
    37 pdu = chr(l) + ''.join(map(chr, buf))
    38 return ''.join(["%02x" % ord(n) for n in pdu])
    39
    40 def encode_SMS (dest_number, text):
    41 # Zaczynamy od szablonu SMSa.
    42 smspdu = "001100"
    43
    44 # Dodajemy długość numeru i jego format.
    45 smspdu += int2hex(len(dest_number)) + '81'
    46
    47 # Dodajemy numer nadawcy.
    48 tmp_number = dest_number
    49 if len(tmp_number) % 2 == 1:
    50 tmp_number += 'F'
    51 i = 0
    52 while i < len(tmp_number):
    53 smspdu = smspdu + tmp_number[i+1] + tmp_number[i]
    54 i += 2
    55
    56 # Dodajemy id protokołu, pole DCS i okres ważności.
    57 smspdu += '0000FF'
    58
    59 # Dodajemy dł. wiadomości no i samą wiadomość :-).
    60 smspdu += int2hex(len(text))
    61 smspdu += encode_message(text)
    62
    63 return smspdu
    Zaletą pythona jest to, że kod w nim napisany jest prawie samo-dokumentujący się. Jeżeli deklarujesz się jako profesjonalny programista, ale jednak nie rozumiesz co się dzieje powyżej, to (nie chce mi się wymyślać żadnych epitetów, po prostu zacytuję pewnego pana):
    to prawdopodobnie masz jeszcze szanse na jakąś karierę, nie wiem, w polityce chyba wiele nie trzeba, musisz tylko dobrze wyglądać w krawacie
    Powyższy kod całkiem dobrze się sprawuje pod warunkiem, że wszystko uda się upakować w jednej wiadomości. W innych wypadkach mogą dziać się różne rzeczy, od bełkotu wyświetlającego się na twojej komórce do niczego - SMS nie dochodzi w ogóle i nikt nie wie dlaczego (sytuacje rodem z politechniki), bramka twierdzi, że wiadomość wysłała, a komórka milczy. Wracając jeszcze raz do dokumentacji szybko znajdujemy informacje jako by przy długich wiadomościach istotną rolę odgrywał tzw. nagłówekUDH. Dodajmy więc małą modyfikację:
     1 message = '\x00\x00\x00\x00\x00\x00' + message
    ...
    ? for i, ch in enumerate (udh):
    ? buf[i] = ord(ch)
    Pierwszą linię dodajemy dokładnie na początku funkcji encode_SMS, a pętlę zaraz po upakowaniu wiadomości (czyli zaraz za pierwszą pętlą we wcześniej opisanej funkcji encode_SMS.

    Na zakończenie powiem coś o sprzęcie. Można zakupić takie urządzenie które nazywa się chyba modemem GPRS. To taki mały pierdolnik podpinany do komputera przez USB i udostępniający mu internet. Nie jestem pewien na 100%, lecz bardzo prawdopodobne, że do tego modemu można podpiąć się za pomocą np. telnetu i wysyłać komendyHayes'a. Ja, szczęśliwie, miałem możliwość obcowania z pełnoprawną bramką GSM, która mieściła w sobie do 30 kart SIM pozwalając nieźle naspamować ]:->. Dziękuję za dotrwanie do końca.