RABBIT 2000

Pozostałe układy mikrokontrolerów, układy peryferyjne i inne, nie mieszczące się w powyższych kategoriach.
Awatar użytkownika
gaweł
Expert
Expert
Posty: 525
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

RABBIT 2000

Postautor: gaweł » poniedziałek 16 kwie 2018, 15:23

Dziwny jest ten świat

...zawracanie gitary, czyli relaks dla emocji...https://www.youtube.com/watch?v=Eh20YY-dFOQ

Ostatnio na tapecie mam tematy sieci ethernetowych w aplikacjach z mikrokontrolerami. No i przypomniałem sobie, że mam taki zestaw, co pozwala na zabawę w temacie. W sumie, to ten zestaw odleżał sobie tak trochę lat, by doczekać się swoich pięciu minut. Pierwszy kontakt (ponad 10 lat temu) był interesujący. Potem historia potoczyła się tak, że … zestaw powędrował gdzieś daleko … na półkę przywalony innymi szpargałami. Ostatnio wypłynął przy okazji jakiegoś sprzątania, więc trafił na mój stół.
rab01-ilu01.jpg
Zakupiłem go sobie kiedyś w ramach fascynacji procesorem Z80, no bo jak się przyjrzeć architekturze tego proca, to widać wyraźnie, że tworzą rodzinę (czyli mają wiele wspólnych genów). Proc został wyprodukowany przez Rabbit Semiconductor. Firma ta, jak podają różne ulotki, powstała w celu zaprojektowania lepszego mikroprocesora do użytku w rozwiązaniach o małych i średnich stopniach komplikacji. Pierwszym mikroprocesorem był Rabbit 2000, kolejny to Rabbit 3000 (w sumie było ich więcej). Rabbit Semiconductor ma wieloletnie doświadczenie w użyciu mikroprocesorów Z80, Z180 i HD64180 do budowy małych sterowników, procki Rabbit mają podobną architekturę i wysoki stopień zgodności z tymi mikroprocesorami.
W kwestii oprogramowania (bo w końcu każdy proc musi coś takiego mieć, inaczej jest tylko kawałkiem bezwartościowego złomu) Rabbit 3000 został zaprojektowany w ścisłej współpracy z Z-World, Inc. Firma ta stworzyła innowacyjny system programowania w języku C (Dynamic C). Z-World dostarcza oprogramowanie narzędziowe dla Rabbit 3000. W materiałach piszą, że pomimo że proc jest 8-bitowy, ma dużą szybkość obliczeń. Piszą również, że do eksperymentów nie są potrzebne emulatory. Rozumiem z tego, że proc posiada w sobie coś, co pozwala całemu światu na kontakt z jego wnętrzem. Dokonuje się tego za pomocą połączenia kabelkiem prostego interfejsu portu szeregowego w PC i systemu docelowego. Pozwala to na programowanie i debugowanie.
W pudełku, oprócz instalki oprogramowania narzędziowego oraz dokumentacji,
rab01-ilu02.jpg
jest plakat.
rab01-ilu03.jpg
Jest podana nazwa strony www, toteż wiedziony potrzebą poszerzenia wiedzy odpalam przeglądarkę internetową. I tu przydarzyła mi się przykra niespodzianka, taki kopniak w czułe miejsce (w końcu jestem sympatykiem zilogowych genów), takiej strony nie ma. Pierwsza myśl: królik zbankrutował? Wujek gugiel poproszony o wyjaśnienie sprawy, nieco rozwiał nadciągające czarne chmury. Jak twierdzi angielska wikipedia, „królicza korporacja” kolaborowała z Dynamic C (no to już wiemy) i 2006 roku została przejęta przez Digi International. Przed zakupem firma Rabbit Semiconductor była częścią Z-World, Inc. No cóż, pewne elementy rzeczywistości przechodzą z rąk do rąk. Widocznie nawet jakaś mała stabilizacja może prowadzić do marazmu, więc czasem musi coś zaiskrzyć by nie odejść w zapomnienie. Może tak było w przypadku królika, gdyż procki te są oferowane nawet dzisiaj (od przejęcia minęło 12 lat). Jakby przyjrzeć się temu co się aktualnie dzieje na świecie, to przejęcia są codziennością (choćby to, że Atmel stał się częścią Microchipa, czy Linear Technology występuje w barwach Analog Devices).
Odwiedzając stronę http://www.digi.com/products/rabbitprocessor
rab01-ilu04.png
widać, że procki Rabbit 2000 są nadal dostępne na rynku.
Posiadany zestaw badawczo-rozwojowy
rab01-ilu05.jpg
zawiera identyczny moduł, jaki jest oferowany przez Digi International.
Przyglądając się modułowi (góra)
rab01-ilu06.jpg
(dół)
rab01-ilu07.jpg
wytworzył mi się w głowie pewien konflikt logiczny. W dokumentacji od proca jest napisane, że to mikroprocesor. Na plakacie jest to przedstawione
rab01-ilu08.jpg
jakby to był mikrokontroler (zawierał w jednej strukturze jakieś peryferale). Kolejne zdziwienie, w króliczym chipie nie ma pamięci Flash ani pamięci RAM (są dodane w module jako komponenty zewnętrzne: 512 kB Flash i 512kB SRAM). Typowo mikrokontroler takie podzespoły integruje w jednej strukturze. Trochę to dziwne, ale … nie będę tego oceniał. Jest, jak jest, należy się do tego dostosować. To, że czegoś do końca nie rozumiem, nie znaczy, że tego nie ma (może kiedyś nadejdzie olśnienie i wszystko stanie się jasne).
Jak zajrzałem na stronę pl.farnell.com, to przeżyłem kolejny szok :shock: , tym razem cenowy. Jakby na to nie patrzeć, zabawa tymi modułami wymaga kupy kasy. No i druga sprawa: niektóre moduły są na wyprzedaży inne wycofane ze sprzedaży. Znaczy się, coś odchodzi do historii (bo w końcu nic nie jest wieczne) i należy poszukiwać nowych rozwiązań (a nie trwać przy swoich przyzwyczajeniach i wyobrażeniach).
Ale zanim ktoś zgasi światło w króliczym świecie, to … może warto zobaczyć jak wygląda ten świat, bo jak twierdzi angielska wikipedia, interesującą cechą króliczej rodziny jest środowisko programistyczne. Dynamic C, wyrosłe razem z prockami Rabbit, jest inne, zawiera swoje dodatki i niespójności w porównaniu ze standardem ANSI-C. Wręcz podąża swoimi własnymi ścieżkami.
Ponieważ standard ANSI-C nie uwzględnia specjalnych potrzeb systemów wbudowanych, konieczne jest odejście od normy w niektórych obszarach i tworzenie nowych w innych. Standard nie uwzględnia ważnych problemów systemów wbudowanych, takich jak pamięć tylko do odczytu i wbudowany język asemblera. Z tego powodu kompilatory przeznaczone dla systemów wbudowanych nie są w pełni zgodne z normą. Jako przykład dodatku, niech posłużą konstrukcje do wielozadaniowości. W Dynamic C są odpowiednie „zaklęcia” na tą okoliczność. Są to costate i slice. Jeszcze nie wiem do czego służą, ale mam nadzieję, że wszystko się wyjaśni. Jak mówią wojskowi: będzie rozpoznanie walką. To powiedzenie mające „militarny wydźwięk” ma zastosowanie w codzienności. Wszystko wymaga jakiegoś wysiłku, samo nie przychodzi. Aby zdobyć kolejny szczyt należy ruszyć swoje cztery litery, wyjść z domu i ruszyć na wycieczkę.
rab01-ilu09.jpg

Nad łóżkiem na ścianie wisi właściwe hasło motywacyjne: Nie narzekaj, że idziesz pod górę skoro zmierzasz na szczyt. No więc wycieczkę zaczynamy od zainstalowania Dynamic C. Instalacja jest typowa i nie zawiera żadnych niespodzianek. Na CD-ku znajdują się pliki z dokumentacją. Okazuje się, że w sieci są bardziej aktualne dane. Są to:
Rabbit 3000 Microprocessor Data Sheet - http://www.acierta-it.com/jas/v3.0/CD%2 ... 3000DS.pdf
Rabbit 3000 Microprocessor User’s Manual - http://datasheets.chipdb.org/Rabbit/3000/R3000UM.pdf
Rabbit 3000 Microprocessor Designer’s Handbook - http://datasheets.chipdb.org/Rabbit/3000/R3000DH.pdf
RabbitCore RCM3400 C-Programmable Analog Core Module with 10/100Base-T Reference Design User’s Manual - http://ftp1.digi.com/support/documentat ... 0122_P.pdf
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Expert
Expert
Posty: 525
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: RABBIT 2000

Postautor: gaweł » wtorek 17 kwie 2018, 22:16

Pierwszy program
rab02_ilu00.jpg

gitarowa nuta
https://www.youtube.com/watch?v=iHS3_q7dlxk


Pierwszy program, pierwsza niedaleka wycieczka w świat Z-WORLD (czy Z WORLD można przetłumaczyć na zaskakujący świat? :) ). Po odpaleniu programu należy utworzyć projekt, opcja File → Project → Create (żadna filozofia).
rab02-ilu01.png
Potem utworzyć plik z programem (File → New). Po wklepaniu tekstu programu plik należy zapisać na dysku (File → Save As). W sumie nic nowego pod słońcem.

Kod: Zaznacz cały

/**********************
Pierwszy projekt dla Rabbit 2000 (Dynamic C)
**********************/

main ( )
{
  unsigned int i , j ;
  //---------------------------------
  i = 0 ;
  for ( ; ; )
  {
    i++ ;
    printf ( "I = %d\n" , i ) ;
    for ( j = 0 ; j < 50000 ; j ++ )
      ;
  } /* for */ ;
} /* main */
Program jest tak prosty, że nawet nie ma gdzie się pomylić.
rab02-ilu02.png
Chciałem jedynie uruchomić kompilację. No więc klik na Compile.
rab02-ilu03.png
I tu pierwsza niespodzianka (ten świat jest dziwny).
rab02-ilu04.png
Nie chce się skompilować, bo … nie widzi króliczego proca. Nie widzi?, niech okulary założy. Pierwszy raz coś mi się takiego przytrafiło, kompilator potrzebuje procka, by skompilować program. Nie rozumiem, ale akceptuję. Podłączam znajdujący się w zestawie kabelek do portu COM w kompie i odpowiednim złączu w zestawie badawczym. Ponowna kompilacja.
rab02-ilu05.png
Kompiler informuje mnie, że kompiluje do pamięci Flash oraz
rab02-ilu06.png
ładuje program do pamięci Flash. Zapewne tej w module, bo sam proc nie ma żadnej pamięci na program. Tu generuje się kilka pytań:
  • przecież do proca może być przypięta pamięć flash o różnej pojemności, skąd Z World wie, jaka jest aktualnie użyta, są przecież różne algorytmu programowania,
  • jak jest programowana ta pamięć, skoro interfejs jest szeregowy i jak widać po kabelku, nie ma zbyt dużo sygnałów do użycia.
Może
  • skoro flash jest w przestrzeni proca (szyna danych proca i szyna adresowa proca) a te nie są wyprowadzone na złącza króliczego modułu, to znaczy, że proc wachluje tymi liniami a to prowadzi do wniosku, że musi być w tym procu jakiś kawałek loadera.
Poza tym, trochę to dziwne, chciałem tylko skompilować, bez ładowania do pamięci. Czy to takie dziwne? Chciałem tylko skompilować a dostałem coś extra niejako w promocji. Skoro program znalazł się w pamięci Flash, to może coś da się podziałać dalej. Klik na Run.
rab02-ilu07.png
Zmieniła się ikonka z Run na Stop, a bieżące okienko przełączyło się na wyświetlanie strumienia stdio.
rab02-ilu08.png
Znaczy, że standardowy strumień wyjściowy programu przełączył się na serial, który jest odbierany i wyświetlany przez środowisko Dynamic C. Jest to z pewnością fajna sprawa, ale czy to oznacza „utratę” jednego UARTU na rzecz stdio (temat do głębszych badań: czy można odpiąć stdio od UART'a, bo może zaistnieć taka potrzeba oraz, czy da się emulować w ten sposób strumień wejściowy, to pozwoli „mieć” klawiaturę w procu przynajmniej w fazie eksperymentów może być przydatne). No to klik na Stop. Program się zatrzymał (znaczy przestał wysyłać coś do strumienia stdio) i przełączył się na okienko w tekstem programu. Ponownie klik na Run. Okazuje się, że program idzie dalej, nie zaczyna od początku.
rab02-ilu09.png
Stop nie znaczy stop? Znaczy się, że źle zrozumiałem? Spodziewałem się, że nastąpi zatrzymanie (programu) a nastąpiła pauza (w programie). Drobna różnica interpretacyjna i w sumie jest to kwestia punktu widzenia. Można to i tak widzieć, zdarza się, że jakieś słowo ma kilka znaczeń.
W takim razie jak uruchomić program od początku? Jest w opcjach Run,
rab02-ilu10.png
ale opcja Reset Pogram jest dostępna tylko w sytuacji, gdy program jest zatrzymany (po Stop). Ponowne uruchomienie programu i … program zaczyna od początku.
Jeszcze jeden eksperyment. Na płycie króliczego zestawu jest przycisk Reset. No więc … do odważnych świat należy.
rab02-ilu11.png
No tak... chyba nie o to chodziło.
Zerwało się połączenie debugera. Po kliknięciu na OK, ponownie klik na Run. Program został ponownie załadowany do pamięci i uruchomiony. W okienku stdio są zapisy. No cóż, taka filozofia, pozostaje się dostosować.
W opcjach znajduję Inspect (zwyczajowo do podglądania stanu zmiennych) i dalej na Add Watch.
rab02-ilu12.png
Wpisuję nazwę zmiennej.
rab02-ilu13.PNG
Implikuje to wyświetlenie
rab02-ilu14.PNG
stanu zmiennej w odpowiednim okienku.
Po każdym zatrzymaniu programu (znaczy w moim rozumieniu: pauzie), odświeżane są informacje w okienku Watches – to miłe.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Expert
Expert
Posty: 525
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: RABBIT 2000

Postautor: gaweł » środa 18 kwie 2018, 12:07

Drugie starcie

Sukces pierwszej wycieczki... rośnie apetyt na więcej. Skoro jest dostępny strumień wyjściowy, to czy daje się prosto użyć strumienia wejściowego w stdio. Utworzony zostaje drugi projekt, z wklepaniem prostego programiku.

Kod: Zaznacz cały

/**********************
Drugi projekt dla Rabbit 2000 (Dynamic C)
**********************/

main ( )
{
  char Ch ;
  //---------------------------------
  for ( ; ; )
  {
    printf ( "\n* * * przed kbhit * * *\n" ) ;
    while ( ! kbhit ( ) )
      ;
    Ch = getchar ( ) ;
    printf ( "\n* * * po kbhit, kod znaku %d * * *\n" , Ch ) ;
  } /* for */ ;
} /* main */
Program jest prosty, że nie powinno być pomyłki. Kompilacja (połączona z ładowaniem kodu do pamięci Flash) i nadchodzi chwila prawdy. Działa.
rab03-ilu01.png
Na klawiaturze peceta naciskam spację (kod znaku 32), klawisz 'a' (małą → kod znaku 97), potem 'A' (wielką → kod znaku 65), potem jakieś inne znaki. Odwzorowane w króliczym wejściowym strumieniu stdio są znaki pisarskie. Próba kombinacji generującej znaki kontrolne nie powodzi się. Wyfiltrowuje je Dynamic C, bo przykładowo na Ctrl-O chce otworzyć plik (File → Open), ale Enter działa. Dobre i to. Takie funkcjonalności stają się inspirujące do kolejnych eksperymentów na przyszłość.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Expert
Expert
Posty: 525
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: RABBIT 2000

Postautor: gaweł » środa 18 kwie 2018, 14:28

Zaskoczony :shock:
El Condor Pasa – wolność i harmonia w przestrzenihttps://www.youtube.com/watch?v=uzBS-dx_wNw
Znalazłem taki przykładowy program z króliczego świata, program do generowania liczb losowych. Zawsze mnie zastanawiało, jak bardzo losowe są liczby losowe? Jakoś trudno mi uwierzyć w prawdziwą losowość, w końcu to obrabia jakiś algorytm, który zawsze wyrachuje identycznie (no chyba, że proc się popsuje i przestanie właściwie realizować operacje arytmetyczne). Z reguły generatory liczb losowych są inicjowane losową liczbą, ale ją też trzeba jakoś … zdobyć. Jeżeli w układzie jest jakiś czynnik ludzki, to może są jakieś szanse. Ot choćby stan inkrementowanego licznika do pierwszego naciśnięcia jakiegoś przycisku. Jednak, jeżeli proc startuje od reseta, zawsze w identycznym środowisku, to… jakoś mi się nie widzi. Znaczy, że w takim układzie losowość jest zdeterminowana? Niby należy spodziewać się nieznanego, a tu wychodzi, że tak miało być, w końcu to algorytm.

Kod: Zaznacz cały

#class auto

// All Dynamic C versions since 8.01 have included the MD5.LIB library, so
//  we can define RAND_USE_MD5 even though we don't demonstrate RAND.LIB's
//  seed_hash() functionality in this sample program.
#define RAND_USE_MD5

// uncomment the following line to make RAND.LIB functions debuggable
//#define RAND_DEBUG

#use "rand.lib"

void main ()
{
   auto char *salt;
   auto unsigned matchValue, testValue;
   auto unsigned long count;

   // initialize the count value to zero for the following comparison
   //  as well as for entry into the while loop later on . . .
   count = 0ul;

   if (memcmp(&SysIDBlock.macAddr[2], &count, sizeof(count))) {
      // if the System ID block contains an actual (non-zero) MAC address,
      //  then use it as our pseudo-random seed "salt" value
      salt = &SysIDBlock.macAddr[2];
   } else {
      // otherwise, don't bother with a psuedo-random seed "salt" value at all
      salt = NULL;
   }
   // NB: An application which requires a secure pseudo random number generator
   //     wouldn't (shouldn't!) call seed_init with anything other than a NULL
   //     "salt" parameter.
   seed_init(salt);

   while (1) {

      // get the pseudo-random integer sequence's next value from our range of
      //  [2000, 2999] inclusive
      testValue = rand16_range(2000u, 1000u);

      // catch and report any (impossible) errors here
      if (2000u > testValue || 2999u < testValue) {
         printf("\n\nError, %u is not in the range [2000, 2999] inclusive!\n\n",
                testValue);
         exception(-ERR_RANGE);
         exit(-ERR_RANGE);
      }

      // display test and / or match values information
      if (count) {
         if (matchValue == testValue) {
            // found a match!
            printf("\n%8u  (Match after %lu pseudo-random sequence values.)\n",
                   testValue, count);
            printf("Press a key to continue.\n");
            while(!kbhit());   // wait for the User to press a key
            getchar();   // throw the keypress away and continue on . . .
            count = 0ul;   // reset the count for the next match test
         } else {
            // no match, just display the test value
            printf("%8u", testValue);
            ++count;
         }
      } else {
         // count is zero so select a new match value to search for
         matchValue = testValue;
         printf("\n%8u  (Searching for the next occurrence of %u.)\n",
                testValue, matchValue);
         ++count;
      }
   }
}
No więc przystępuję do kompilacji, a tu … niespodzianka.
rab04-ilu01.png
Myszka mi się omsknęła i wybrałem inną opcję: Compile → Compile to .bin File → Compile to Flash.
W dziwnym świecie, uruchomiła się kompilacja, która jak sugeruje tytuł okienka, nie wymaga systemu docelowego.
rab04-ilu02.png
Mało tego, nawet się poprawnie skompilowało.
rab04-ilu04.png
No to spróbowałem z odłączonym zestawem. Wyszło identycznie. Prosty wniosek, nie zawsze potrzebny jest układ docelowy. No cóż, należy uderzyć się w pierś i przyznać, że... chyba trochę naurągałem króliczemu światu i należą się jakieś przeprosiny. Więc przepraszam króliczy świat :) . Można to rozpatrywać w kategoriach losowości i prawdopodobieństwa. Eksperymentując z algorytmem generującym liczby losowe, zaistniało zjawisko losowe. Co za ironia. A może tak miało być i było to zdeterminowane? Tak gwoli ścisłości, wracając do króliczego świata, to nie czuję się bym w czymś zawinił. Ot, bazując na obserwacji został wyciągnięty jakiś wniosek, który później okazał się błędny. Tak bywa, jeżeli wiedzę zdobywa się w kategoriach wojskowych: rozpoznanie walką. No niby można było zajrzeć do dokumentacji, ale... nie istotne. Jest jak jest. Jeszcze czeka wiele potyczek, bo każdy manual nie zawiera odpowiedzi na wszystkie możliwe pytania i trzeba samemu się natrudzić by poznać wszystkie odpowiedzi. Po załadowaniu programu do systemu docelowego, wyszło
rab04-ilu05.PNG
Czy są to liczby losowe? Może tak, może nie, kwestia punku widzenia.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Expert
Expert
Posty: 525
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: RABBIT 2000

Postautor: gaweł » środa 18 kwie 2018, 20:29

Wielozadaniowe starcie
Wielozadaniowa nutahttps://www.youtube.com/watch?v=YbF_yB57IwI
W Dynamic C zostało wprowadzonych kilka rozwiązań spoza normy ANSI C mające zastosowanie dla wielozadaniowości. Wielozadaniowość, to tak jakby w króliczym procku zostało uruchomionych kilka programów, które międlą się równolegle. Ogólnie wiadomo, że jest to jakaś iluzja, bo klasyczne procki są sekwencyjne (realizują instrukcje programu sekwencyjnie). W rzeczywistości wielozadaniowość jest realizowana w ten sposób, że czas procesora jest cyklicznie przydzielany kolejnym potokom programu. W środowisku wielozadaniowym występuje więcej niż jedno zadanie (każde reprezentujące swoją sekwencję operacji), które mogą wydawać się, że są wykonywane równolegle. W rzeczywistości pojedynczy procesor w danej chwili może wykonywać tylko jedną instrukcję. Każde zadanie może wykonać część swojej pracy, podczas gdy inne zadania (potoki) czekają na jakieś zdarzenie lub na coś do zrobienia. Jeżeli przełączanie następuje szybko, to uzyskuje się pozór wykonywania równoległego iluś zadań.
W przypadku braku wielozadaniowego systemu operacyjnego, programista, który rozwiązuje problem jako wielozadaniowy, często wymyśla rozwiązanie, które można opisać jako maszyny stanu przełączane z dużą prędkością. Oznacza to, że program składa się z dużej, nieskończonej pętli. Wewnątrz tej pętli zadania są wykonywane przez małe fragmenty programu, które przechodzi przez serię stanów. Maszyny stanów mogą stać się dość skomplikowane, obejmujące dużą liczbę zmiennych stanu i dużą liczbę stanów. Zaletą automatu stanów jest to, że unika on ciągłego oczekiwania, które czeka w pętli, dopóki warunek nie zostanie spełniony. W ten sposób jedna wielka pętla może obsługiwać dużą liczbę maszyn stanów, z których każda wykonuje swoje własne zadanie, a nikt nie jest zajęty czekaniem. Współpracujące wielozadaniowe rozszerzenia językowe dodane do Dynamic C używają wielkiej pętli i koncepcji maszyny stanów. Stan zadania jest pamiętany przez wskaźnik instrukcji, który zapisuje miejsce, w którym wykonanie bloku instrukcji zostało wstrzymane w oczekiwaniu na zdarzenie.
W Dynamic C występuje rozszerzenie językowe wspierające prostą wielozadaniowość. Do tego służy zaklęcie costate. Postać zapisu jest następująca:
costate [ name [state] ] { [ statement ; | yield ; | abort ; | waitfor ( expression ) ; ] . . .}
gdzie :
  • costate jest słowem kluczowym,
  • name (jest opcjonalne) i oznacza nazwę ciągu costate, brak nazwy oznacza, że costate jest nienazwane,
  • state (jest opcjonalne) – stan może być jednym z następujących: always_on lub init_on (znaczenie tego z dokumentacji jest trochę niejasne, więc trzeba będzie rozpoznać to walką), nienazwane ciągi costatealways_on,
  • statement – to ciąg instrukcji języka,
  • yield – dodane w Dynamic C słowo kluczowe, którego zadaniem jest przełączenie na kolejne costate,
  • abort – dodane w Dynamic C słowo kluczowe, którego zadaniem jest zaniechanie realizacji ciągu costate,
  • waitfor ( expression ) – dodane w Dynamic C słowo kluczowe (to nie jest wywołanie funkcji), którego zadaniem jest zawieszenie danego costate do chwili zajścia warunku określonego przez expression.
No, to jak wygląda to w praniu. Powstaje program:

Kod: Zaznacz cały

main ( )
{
  int i ;
  //---------------------------------------------------------------
  for ( ; ; )
  {
    costate
    {
      for ( i = 0 ; i < 30000 ; i++ )
      {
        yield ;
      }
    }
    costate
    {
      waitfor ( DelayMs ( 500 ) ) ;
      printf ( "i = %d\n" , i ) ;
    }
  }
}
Kompilacja programu (połączona z załadowaniem go do pamięci flash). Po uruchomieniu programu jego strumień wyjściowy stdio wygląda następująco:

Kod: Zaznacz cały

i = 14011                                                                       
i = 28013                                                                       
i = 12032                                                                       
i = 26051                                                                       
i = 10066                                                                       
i = 24063                                                                       
i = 8081                                                                       
i = 22104                                                                       
i = 6121                                                                       
i = 20143                                                                       
i = 4163                                                                       
i = 18162                                                                       
i = 2178                                                                       
i = 16199                                                                       
i = 217                                                                         
i = 14243                                                                       
i = 28265                                                                       
i = 12285                                                                       
i = 26278                                                                       
i = 10298                                                                       
i = 24319                                                                       
i = 8337                                                                       
i = 22362                                                                       
i = 6382                                                                       
i = 20380                                                                       
i = 4395                                                                       
i = 18417
W programie są dwa zadania: jedno inkrementuje ciągle liczbę, drugie co pól sekundy „drukuje” tą liczbę do strumienia stdio. W wynikach widać jakiś asynchronizm, zdarzenie upłynięcia czasu w jednym ciągu costate, „trafia” drugi ciąg costate w różnych stanach.
Drobna modyfikacja programu (usuwamy zaklęcia yield).

Kod: Zaznacz cały

main ( )
{
  int i ;
  //---------------------------------------------------------------
  for ( ; ; )
  {
    costate
    {
      for ( i = 0 ; i < 30000 ; i++ )
        ;
    }
    costate
    {
      waitfor ( DelayMs ( 500 ) ) ;
      printf ( "i = %d\n" , i ) ;
    }
  }
}
Tym razem wynik jest następujący:

Kod: Zaznacz cały

i = 30000                                                                       
i = 30000                                                                       
i = 30000                                                                       
i = 30000                                                                       
i = 30000                                                                       
i = 30000                                                                       
i = 30000                                                                       
i = 30000                                                                       
i = 30000
Wychodzi, że yield (jak jest) za każdym obrotem pętli przełącza zadanie na inne (wtedy wychodzi asynchronizm wydruków). Jeżeli jest brak yield, to pętla wykonuje się do końca i dopiero wtedy przełącza się na inne zadanie.
No to jeszcze inny eksperyment:

Kod: Zaznacz cały

#define LEDON   1
#define LEDOFF   0

int ledstatus;

leds_setup ( )
{
   ledstatus = PDDRShadow | 0xC0 ;
   WrPortI( PDDR , & PDDRShadow , ledstatus ) ;
}


LED1 ( int what )
{
   if ( what == LEDON )
      ledstatus &= 0xBF ;
   else
      ledstatus |= 0x40 ;
   WrPortI ( PDDR , NULL , ledstatus ) ;
}


LED2 ( int what )
{
   if ( what == LEDON )
      ledstatus &= 0x7F ;
   else
      ledstatus |= 0x80 ;
   WrPortI ( PDDR , NULL , ledstatus ) ;
}


main ( )
{
  //---------------------------------------------------------------
  brdInit ( ) ;
  leds_setup ( ) ;
  for ( ; ; )
  {
    costate
    {
      waitfor ( DelayMs ( 500 ) ) ;
      LED1 ( LEDON ) ;
      yield ;
      waitfor ( DelayMs ( 500 ) ) ;
      LED1 ( LEDOFF ) ;
      yield ;
    }
    costate
    {
      waitfor ( DelayMs ( 300 ) ) ;
      LED2 ( LEDON ) ;
      yield ;
      waitfor ( DelayMs ( 300 ) ) ;
      LED2 ( LEDOFF ) ;
      yield ;
    }
  }
}
Po uruchomieniu programu w króliczym zestawie, oba LED'y mrugają każdy swoim, innym rytmem. Mam wrażenie, że zaczynam rozumieć filozofię costate.
rab05-ilu01.jpg
Tak trochę w technologii „rzutu na taśmę”, postanowiłem usunąć z programy wszystkie instrukcje yield, zobaczymy co z tego wychodzi. Istotna część wygląda następująco:

Kod: Zaznacz cały

main ( )
{
  //---------------------------------------------------------------
  brdInit ( ) ;
  leds_setup ( ) ;
  for ( ; ; )
  {
    costate
    {
      waitfor ( DelayMs ( 500 ) ) ;
      LED1 ( LEDON ) ;
      waitfor ( DelayMs ( 500 ) ) ;
      LED1 ( LEDOFF ) ;
    }
    costate
    {
      waitfor ( DelayMs ( 300 ) ) ;
      LED2 ( LEDON ) ;
      waitfor ( DelayMs ( 300 ) ) ;
      LED2 ( LEDOFF ) ;
    }
  }
}
Po uruchomieniu, całość zachowuje się identycznie. Może zaklęcie waitfor zawiera w sobie już yield? Miałoby to sens.
Reasumując na zakończenie, funkcjonalnie trochę przypomina to filozofię z MODULA 2, z tym, że tam jako task występuje wskazana procedura, a tutaj jest to jakiś fragment ujęty w nawiasy { } poprzedzony zaklęciem costate.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Expert
Expert
Posty: 525
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: RABBIT 2000

Postautor: gaweł » czwartek 19 kwie 2018, 22:14

Ostatni program, ten do mrugania diodami LED, rzeczywiście znajduje się w pamięci nieulotnej.
rab06-ilu01.jpg
Device przeleżało przez noc bez prądu i obecnie jedynie z przyłączonym kabelkiem od zasilania wstało samodzielnie na nogi. Właściwie nic w tym dziwnego, można się tego spodziewać, ale o wszystkim się trzeba przekonać samemu.
Króciutki filmik:
rabbit6.mov
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Expert
Expert
Posty: 525
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: RABBIT 2000

Postautor: gaweł » piątek 20 kwie 2018, 02:42

Szersze wody
rab07-ilu00.jpg

Nie ma to jak harmonia.https://www.youtube.com/watch?v=3J0_mnFsdso
Dreptanie po najbliższej okolicy staje się mało ciekawe. Nadeszła pora sięgnąć po więcej. Te więcej, to już całkiem spory teren, obejmuje swym zasięgiem 3 kondygnacje, w końcu kabelek eternetowy rozchodzi się po całej chałupie. Z punktu widzenia sieci istotne elementy środowiska pokazuje następujący rysunek:
rab07_ilu01.png
Korzystając z maleńkiego króliczego multitaskingu, powstaje niby prosty program. Prosty, bo nic skomplikowanego nie robi, jednak, gdy zajrzeć pod maskę, to widać ogrom wykonanej programowej pracy. Taki niepozorny ping w rzeczywistości to ogrom działań, których nie widać. Zagłębiając się w szczegóły dopiero można dostrzec złożoność zagadnienia, jednak nie każdy ma ochotę poznać prawdziwe oblicze tego świata. Przechodzenie informacji przez poszczególne warstwy modelu OSI, zrozumienie mechanizmów komunikacji, itp. to całkiem spore wyzwanie. Ten cały ogrom działań jest rzeczywisty, istnieje. By go dostrzec wystarczy zmienić swój własny fokus, wyrazić chęć a pomocna dłoń z pewnością się znajdzie.
Mając pewne doświadczenia w czarowaniu w króliczej przestrzeni, tworzę nowy program. Rzecz jasna musi zachodzić synergia i konsensus pomiędzy poszczególnymi elementami. Naukę komunikacji należy zacząć od podstawowego poziomu i dogadać się z biblioteką procedur. W świecie Z (Z WORLD) całość jest podana źródłowo, więc można go adaptować do własnych potrzeb i na tej bazie wyprodukować swój własny maleńki świat. Ktoś już zadbał i stworzył ileś wariantów, nam zostało wybrać jeden, ten właściwy.
W pliku TCP_CONFIG.LIB (plik jest w rzeczywistości zapisem źródłowym) jest zawarte kreowanie rzeczywistości na podstawie wymagań programisty. Nadając stałej o nazwie TCPCONFIG odpowiednią wartość można uzyskać różne rozwiązania. Przykładowo dla:
  • TCPCONFIG = 1 – mamy typową sieć ethernetową o ustalonych parametrach (własny adres IP, maska podsieci, adres IP bramy domyślnej, adres serwera DNS),
  • TCPCONFIG = 2 – mamy sieć PPP bazującą na porcie szeregowym C,
  • TCPCONFIG = 3 – mamy sieć sieć ethernetową konfigurowaną automatycznie (DHCP).
Dostosowałem jedynie wstępną propozycję do własnych potrzeb. W końcu każdy jest przecież indywidualnością (istotny fragment TCP_CONFIG.LIB):

Kod: Zaznacz cały

//   #define _PRIMARY_STATIC_IP      "10.10.6.100"
//   #define _PRIMARY_NETMASK      "255.255.255.0"
//   #ifndef MY_NAMESERVER
//      #define MY_NAMESERVER      "10.10.6.1"
//   #endif
//   #ifndef MY_GATEWAY
//      #define MY_GATEWAY         "10.10.6.1"
//   #endif
   #define _PRIMARY_STATIC_IP      "192.168.0.44"
   #define _PRIMARY_NETMASK      "255.255.255.0"
   #ifndef MY_NAMESERVER
      #define MY_NAMESERVER      "192.168.0.254"
   #endif
   #ifndef MY_GATEWAY
      #define MY_GATEWAY      "192.168.0.254"
   #endif
Przy takim rozwiązaniu we własnym programie wystarczy zdefiniować stałą w następujący sposób:

Kod: Zaznacz cały

#define TCPCONFIG  1
i w króliczym środowisku jest sieć o wymaganych cechach.
Program do eksperymentów jest następujący:

Kod: Zaznacz cały

#define PORTA_AUX_IO
#class auto

#define TCPCONFIG 1
#define PING_WHO         "51.255.157.203"
//"192.168.0.67"

#define PING_DELAY      2000

#memmap xmem
#use "dcrtcp.lib"

#define LEDON   1
#define LEDOFF   0

int ledstatus ;

leds_setup ( )
{
   ledstatus = PDDRShadow | 0xC0 ;
   WrPortI ( PDDR , & PDDRShadow , ledstatus ) ;
} /* leds_setup */


pingoutled ( int NewState )
{
  if ( NewState == LEDON )
    ledstatus &= 0xBF ;
  else
    ledstatus |= 0x40 ;
  WrPortI ( PDDR , NULL , ledstatus ) ;
} /* pingoutled */


pinginled ( int NewState )
{
  if ( NewState == LEDON )
    ledstatus &= 0x7F ;
  else
    ledstatus |= 0x80 ;
  WrPortI ( PDDR , NULL , ledstatus ) ;
} /* pinginled */


main ( )
{
  longword seq ;
  longword ping_who ;
  longword tmp_seq ;
  longword time_out ;
  word Valid ;
  word NewHostData ;
  word Loop ;
  char Ch ;
  char * PCh ;
  char HostIP [ 40 ] ;
  char TmpHostIP [ 40 ] ;
  char buffer [ 100 ] ;
  //-----------------------------------------------------------------
  brdInit ( ) ;
  seq = 0 ;
  leds_setup ( ) ;
  sock_init ( ) ;
  printf( "Moj adres IP = %s\n" ,
          inet_ntoa ( buffer , gethostid ( ) ) ) ;
  printf( "Adres IP DNS = %s\n" , MY_NAMESERVER ) ;
  printf( "Adres IP GW = %s\n" , MY_GATEWAY ) ;
  printf( "\n\n" ) ;
  strcpy ( HostIP , PING_WHO ) ;
  NewHostData = 1 ;
  Valid = 0 ;
  for ( ; ; )
  {
    if ( NewHostData )
    {
      NewHostData = 0 ;
      ping_who = resolve ( HostIP ) ;
      if ( ping_who == 0 )
      {
        Valid = 0 ;
        printf ( "Blad: cos krzywo jest wklepane: %s\n" , HostIP ) ;
      } /* if ... */
      else
      {
        Valid = 1 ;
        printf ( "\nPingowanie hosta IP=%s\n\n" , HostIP ) ;
      } /* if ... else */ ;
    } /* if */ ;
    tcp_tick ( NULL ) ;
    costate
    {
      if ( Valid )
      {
        waitfor ( DelayMs ( PING_DELAY ) ) ;
        printf ( "Ping wyslany do %s\n" , HostIP ) ;
        _ping ( ping_who , seq++ ) ;
        pingoutled ( LEDON ) ;
        waitfor ( DelayMs ( 50 ) ) ;
        pingoutled ( LEDOFF ) ;
      } /* if */ ;
    } /* costate */
    costate
    {
      if ( Valid )
      {
        time_out = _chk_ping ( ping_who , & tmp_seq ) ;
        if ( time_out != 0xffffffff )
        {
          printf ( "Odebrano odpowiedz na ping: %ld\n" , tmp_seq ) ;
          pinginled ( LEDON ) ;
          waitfor ( DelayMs ( 50 ) ) ;
          pinginled ( LEDOFF ) ;
        } /* if */
      } /* if */ ;
    } /* costate */ ;
    costate
    {
      if ( kbhit ( ) )
      {
        for ( Loop = 0 ; Loop < 40 ; Loop ++ )
          TmpHostIP [ Loop ] = 0 ;
        PCh = TmpHostIP ;
        Ch = getchar ( ) ;
        * PCh ++ = Ch ;
        for ( ; ; )
        {
          if ( ! kbhit ( ) )
            yield ;
          else
          {
            Ch = getchar ( ) ;
            if ( Ch < 0x20 )
            {
              * PCh = 0 ;
              NewHostData = 1 ;
              printf ( "\n\nNowy host: %s\n\n" , TmpHostIP ) ;
              strcpy ( HostIP , TmpHostIP ) ;
              break ;
            } /* if ... */
            else
            {
              * PCh ++ = Ch ;
              printf ( "\nMasz wklepane: %s\n" , TmpHostIP ) ;
            } /* if ... else */ ;
          } /* if ... else */ ;
        } /* for */ ;
      } /* if */ ;
    } /* costate */ ;
  } /* for */ ;
} /* main */
W programie są trzy taski:
  • do wysyłania ping,
  • do odbierania ping,
  • do wklepania nowego adresu IP do pingowania (wykorzystując króliczy wejściowy strumień stdio), który wstępnie jest określony na przykładowy adres IP=51.255.157.203 (adres IP wskazujący na elportal.pl), można go poznać wysyłając sygnał ping z kompa:
    rab07_ilu02.png
Uruchomiony program wygenerował następujące wyniki:
Moj adres IP = 192.168.0.44
Adres IP DNS = 192.168.0.254
Adres IP GW = 192.168.0.254

Pingowanie hosta IP=51.255.157.203

Ping wyslany do 51.255.157.203
Odebrano odpowiedz na ping: 0
Ping wyslany do 51.255.157.203
Odebrano odpowiedz na ping: 1
(...)

Masz wklepane: 19
Masz wklepane: 192
Masz wklepane: 192.
Masz wklepane: 192.1
Masz wklepane: 192.16
Masz wklepane: 192.168
Ping wyslany do 51.255.157.203
Odebrano odpowiedz na ping: 11

Masz wklepane: 192.168.
Masz wklepane: 192.168.0
Masz wklepane: 192.168.0.
Ping wyslany do 51.255.157.203
Odebrano odpowiedz na ping: 12

Masz wklepane: 192.168.0.6
Masz wklepane: 192.168.0.67

Nowy host: 192.168.0.67


Pingowanie hosta IP=192.168.0.67

Ping wyslany do 192.168.0.67
Odebrano odpowiedz na ping: 13
(...)

Masz wklepane: 19
Masz wklepane: 192
Masz wklepane: 192.
Masz wklepane: 192.1
Masz wklepane: 192.16
Ping wyslany do 192.168.0.67
Odebrano odpowiedz na ping: 22

Masz wklepane: 192.168
Masz wklepane: 192.168.
Masz wklepane: 192.168.0
Masz wklepane: 192.168.0.
Masz wklepane: 192.168.0.2
Masz wklepane: 192.168.0.25
Ping wyslany do 192.168.0.67
Odebrano odpowiedz na ping: 23

Masz wklepane: 192.168.0.254

Nowy host: 192.168.0.254


Pingowanie hosta IP=192.168.0.254

Ping wyslany do 192.168.0.254
Odebrano odpowiedz na ping: 24
Ping wyslany do 192.168.0.254
Odebrano odpowiedz na ping: 25

Ze swego kompa (192.168.0.67) daje się sięgnąć do świata królika (PING 192.168.0.44):
rab07_ilu03.png

No zaczyna robić się coraz ciekawiej :)
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Expert
Expert
Posty: 525
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: RABBIT 2000

Postautor: gaweł » piątek 20 kwie 2018, 22:30

Mówimy jedno, myślimy o innym
Pianino ma coś ze szlachetności...https://www.youtube.com/watch?v=Z4xSbNAMKIA
Sieć internet, ta kojarzona ze stronami www (by nie było niejednoznaczności interpretacyjnej), to jedno z zastosowań całej gamy możliwych użyć sieci ethernetowej. By sięgnąć po zawartość strony, należy nawiązać połączenie TCP na ściśle określony numer portu. Takie, dobrze skierowane „poproszę”. W odpowiedzi (na to poproszę) przyjdzie samo. O cokolwiek poprosimy, aby tylko dobrze skierować pytanie, przyjdzie. Niestety wymaga to pewnych zabiegów, bo jak chcemy coś od microgeek.eu, to należy zapytać eeee.... no właśnie, kogo?
Do eksperymentu powstaje odpowiedni program:

Kod: Zaznacz cały

#define PORTA_AUX_IO
#class auto
 /***************************************************
 * moj adres IP jest  192.168.0.44                  *
 * maska podsieci jest 255.255.255.0                *
 * brama domyslna jest 192.168.0.254                *
 * serwer DNS jest 192.168.0.254                    *
 ****************************************************/
#define TCPCONFIG 1

#use dcrtcp.lib

void DNSResolve ( char * HostName )
{
  longword HostIP ;
  char Buffer [ 20 ] ;
  //---------------------------------------------------------------------------
     HostIP = resolve ( HostName ) ;
     if ( HostIP == 0 )
      printf ( "\nNie mozna znalezc adresu IP dla domeny %s\n" , HostName ) ;
    else
   {
     inet_ntoa ( Buffer , HostIP ) ;
     printf ( "\nAdres domeny %s jest %s\n" , HostName , Buffer ) ;
   } /* if ... else */ ;
} /* DNSResolve */


void main ( )
{
  char Buffer [ 32 ] ;
  //---------------------------------------------------------------------------
  sock_init ( ) ;
  printf( "Moj adres IP = %s\n" ,
          inet_ntoa ( Buffer , gethostid ( ) ) ) ;
  printf( "Adres IP DNS = %s\n" , MY_NAMESERVER ) ;
  printf( "Adres IP GW = %s\n" , MY_GATEWAY ) ;
  printf( "\n\n" ) ;
  DNSResolve ( "microgeek.pl" ) ;
  DNSResolve ( "microgeek.com" ) ;
  DNSResolve ( "microgeek.eu" ) ;
  DNSResolve ( "elportal.pl" ) ;
  DNSResolve ( "kamami.pl" ) ;
  DNSResolve ( "btc.pl" ) ;
  DNSResolve ( "onet.pl" ) ;
  DNSResolve ( "google.com" ) ;
} /* main */
Do programu wklepuję kila różnych nazw domen (istniejące i nieistniejące). Standardowo: kompilacja, załadowanie do pamięci flash, uruchomienie daje:
Moj adres IP = 192.168.0.44
Adres IP DNS = 192.168.0.254
Adres IP GW = 192.168.0.254

Nie mozna znalezc adresu IP dla domeny microgeek.pl

Adres domeny microgeek.com jest 103.224.182.216

Adres domeny microgeek.eu jest 194.181.20.135

Adres domeny elportal.pl jest 51.255.157.203

Adres domeny kamami.pl jest 94.152.188.251

Adres domeny btc.pl jest 212.85.125.51

Adres domeny onet.pl jest 213.180.141.140

Adres domeny google.com jest 216.58.215.78

I tak przykładowo, mówimy microgeek.eu a myślimy 194.181.20.135, A przynajmniej w chwili powstawania tego tekstu tak było, bo to może się zmienić. No nic nie jest stałe i trwałe, no czysta alchemia.
Tak korciło mnie, by sprawdzić te informacje (ja wszystko sprawdzam). No więc odpalam okienko cmd:
rab08_ilu01.png
Królik twierdzi, że: Adres domeny microgeek.eu jest 194.181.20.135, ping w windozie potwierdza to. Wniosek: nie kłamie, mówi prawdę. Hmmm, właściwie, to nie opcji by mijał się z prawdą. A tak przy okazji, nie odpowiada na pingowe zaczepki. Wolno mu, w końcu nie ma obowiązku.
Analogicznie:
Microsoft Windows XP [Wersja 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

E:\microgeek>ping elportal.pl

Badanie elportal.pl [51.255.157.203] z użyciem 32 bajtów danych:

Odpowiedź z 51.255.157.203: bajtów=32 czas=58ms TTL=53
Odpowiedź z 51.255.157.203: bajtów=32 czas=58ms TTL=53
Odpowiedź z 51.255.157.203: bajtów=32 czas=45ms TTL=53
Odpowiedź z 51.255.157.203: bajtów=32 czas=54ms TTL=53

Statystyka badania ping dla 51.255.157.203:
Pakiety: Wysłane = 4, Odebrane = 4, Utracone = 0 (0% straty),
Szacunkowy czas błądzenia pakietów w millisekundach:
Minimum = 45 ms, Maksimum = 58 ms, Czas średni = 53 ms

E:\microgeek>

Zgada się: Odpowiedź z 51.255.157.203: bajtów=32 czas=58ms TTL=53Adres domeny elportal.pl jest 51.255.157.203.
Kolejna pozycja:
Microsoft Windows XP [Wersja 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

E:\microgeek>ping btc.pl

Badanie btc.pl [212.85.125.51] z użyciem 32 bajtów danych:

Odpowiedź z 212.85.125.51: bajtów=32 czas=32ms TTL=56
Odpowiedź z 212.85.125.51: bajtów=32 czas=32ms TTL=56
Odpowiedź z 212.85.125.51: bajtów=32 czas=30ms TTL=56
Odpowiedź z 212.85.125.51: bajtów=32 czas=29ms TTL=56

Statystyka badania ping dla 212.85.125.51:
Pakiety: Wysłane = 4, Odebrane = 4, Utracone = 0 (0% straty),
Szacunkowy czas błądzenia pakietów w millisekundach:
Minimum = 29 ms, Maksimum = 32 ms, Czas średni = 30 ms

E:\microgeek>

Pasuje: Badanie btc.pl [212.85.125.51]Adres domeny btc.pl jest 212.85.125.51.
Również prawdziwe, do bólu.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Expert
Expert
Posty: 525
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: RABBIT 2000

Postautor: gaweł » sobota 21 kwie 2018, 02:00

Tak już na luzie, idzie się dogadać
Coffee Music – Relaxinghhttps://www.youtube.com/watch?v=IaLjxetQcXw

Dotychczas adresy IP były usztywnione. Rzecz jasna, czasami bywa to przeszkadzające. Powołany do istnienia byt (króliczy) może być nienazwany, taka swoista tabula raza. Jednak do egzystowania należy posiadać „imię”. W zasobach płyty CD dodanym do zestawu, natrafiłem na odpowiedni przykład, który został lekko zmodyfikowałem (kosmetyka).
Eksperyment związany z poznaniem własnej tożsamości, program:

Kod: Zaznacz cały

#class auto

#define PORTA_AUX_IO

/*
 * Pick the predefined TCP/IP configuration for this sample.  See
 * LIB\TCPIP\TCP_CONFIG.LIB for instructions on how to set the
 * configuration.
 * Config #5 = simple blank-slate DHCP, with fallbacks
 */
#define TCPCONFIG      5

/*
 * Define this symbol to force BOOTP protocol (not DHCP).  This is useful
 * when code space is tight.  You may need to specially configure your
 * DHCP server to respond to BOOTP-only clients.
 */
//#define BOOTP_ONLY

/*
 * General debugging options...
 */
//#define BOOTP_DEBUG      // Allow Dynamic C debugging in bootp.lib
//#define BOOTP_VERBOSE      // Print lots of detail
//#define ICMP_VERBOSE

/*
 * Specify information to obtain from DHCP server...
 */
#define DHCP_NUM_SMTP 1      // Get an SMTP server if possible
#define DHCP_NUM_ROUTERS 2   // Get up to 2 routers (gateways) if possible
#define DHCP_NUM_DNS  2      // Get up to 2 DNS (Domain Name System) servers if possible
#define DHCP_NUM_QOTD 2      // Get up to 2 cookie (Quote Of The Day) servers if possible
#define MAX_COOKIES 2      // Also need to tell main tcp lib (default is 1).



// Min DHCP retry interval (secs).  If not defined, defaults to 60.
#define DHCP_MINRETRY 5

// This define causes boot image file to be downloaded.  The value
// specifies the maximum number of bytes to download.  This should
// be less than about 32k to avoid running out of extended memory.
// You will need to configure your server to specify the file to
// download.
#define DHCP_USE_TFTP (3*512+5)
#define TFTP_ALLOW_BUG      // Work-around certain TFTP server upload bug

// This optional string will be sent to the DHCP server as the
// 'class identifier' of this host.  This allows the server to
// "know what it's dealing with".  There is no particular standard
// for this string, but for ease of management Z-World suggests
// colon-separated fields in the form "hardware platform:vendor:
// firmware identifier:version number".  Your DHCP server can be
// configured to recognise these strings in order to select
// appropriate parameters. [NB: it is expected that this string
// be the same for all clones, i.e. not customised for each unit
// of the same product -- the ethernet hardware address is unique
// for each unit and thus identifies particular 'individuals' to
// the DHCP server.  Think of class ID as identifying the "what" but
// not the "who"].
#define DHCP_CLASS_ID "Rabbit-TCPIP:Z-World:DHCP-Test:1.0.0"

// This macro causes the MAC address to be used as a unique client
// identifier.
#define DHCP_CLIENT_ID_MAC

#memmap xmem
#use dcrtcp.lib


/*
 * Print some of the DHCP or BOOTP parameters received.
 */
static void print_results(void)
{
   auto long tz;
   auto word i;
   char Buffer [ 20 ] ;

   printf("Network Parameters:\n");
   printf("  My IP Address = %08lX [%s]\n", my_ip_addr, inet_ntoa(Buffer,my_ip_addr)) ;
   printf("  Netmask = %08lX [%s]\n", sin_mask, inet_ntoa(Buffer,sin_mask)) ;
   if (_dhcphost != ~0UL) {
      if (_dhcpstate == DHCP_ST_PERMANENT) {
         printf("  Permanent lease\n");
      } else {
         printf("  Remaining lease = %ld (sec)\n", _dhcplife - SEC_TIMER);
         printf("  Renew lease in %ld (sec)\n", _dhcpt1 - SEC_TIMER);
      }
      printf("  DHCP server = %08lX [%s]\n", _dhcphost, inet_ntoa(Buffer,_dhcphost)) ;
      printf("  Boot server = %08lX\n", _bootphost);
   }
   if (gethostname(NULL,0))
      printf("  Host name = %s\n", gethostname(NULL,0));
   if (getdomainname(NULL,0))
      printf("  Domain name = %s\n", getdomainname(NULL,0));
   if (dhcp_get_timezone(&tz))
      printf("  Timezone (fallback only) = %ldh\n", tz / 3600);
   else
      printf("  Timezone (DHCP server) = %ldh\n", tz / 3600);
   for (i = 0; i < *_last_nameserver; i++)
      printf("  DNS server #%u = %08lX [%s]\n", i+1, def_nameservers[i], inet_ntoa(Buffer,def_nameservers[i])) ;
   if (_smtpsrv)
      printf("  SMTP server = %08lX\n", _smtpsrv);
   for (i = 0; i < _last_cookie; i++)
      printf("  Cookie server #%u = %08lX\n", i+1, _cookie[i]);
//   ip_print_ifs();
//   router_printall();
}

void main()
{
   longword st;
   longword rls;
   char bounced;
   char pboot;
   char putback;
   struct tftp_state ts;
   int status;
   word bflen;

   pboot = false;      // Not yet printed boot file
   putback = false;   // Not yet echoed boot file to server
   bounced = false;   // Not yet released/re-acquired DHCP parameters

   // Set runtime control for sock_init()...
   ifconfig(IF_DEFAULT,         // (DHCP only works on default interface)
      IFS_DHCP_TIMEOUT, 6,      // Specify timeout in seconds
      IFS_DHCP_FALLBACK, 1,   // Allow use of fallbacks to static configuration
      IFS_ICMP_CONFIG, 1,      // Also allow use of directed ping to configure (only if DHCP times out).
      IFS_END);

   printf("Starting network (max wait %d seconds)...\n", _bootptimeout);

   status = sock_init();

   switch (status) {
      default:
         break;
      case 1:
         printf("Could not initialize packet driver.\n");
         exit(1);
      case 2:
         printf("Could not configure using DHCP.\n");
         break;   // continue with fallbacks
      case 3:
         printf("Could not configure using DHCP; fallbacks disallowed.\n");
         exit(3);
   }

   if (_dhcphost != ~0UL)
      printf("Lease obtained\n");
   else {
      printf("Lease not obtained.  DHCP server may be down.\n");
      printf("Using fallback parameters...\n");
   }
   print_results();

   rls = SEC_TIMER + 90;   // In 1.5 minutes relinquish lease.

   for (;;) {

      // Check lease has not expired
      if (!tcp_tick(NULL)) {
         printf("Network down; bringing up in 2 secs...\n");
         st = SEC_TIMER + 2;
         while (SEC_TIMER < st);
         if (!(status = dhcp_acquire())) {
            printf("Network back up\n");
            print_results();
         }
         else if (status == 1) {
            printf("Network back up but with DIFFERENT IP address\n");
            print_results();
         }
         else {
            printf("Network lost.  DHCP server probably down.\n");
            exit(78);
         }
      }

      // Some time after boot, "bounce" the network (just once).
      if (!bounced && SEC_TIMER > rls) {
         bounced = true;
         //dhcp_release();
         ifconfig(IF_DEFAULT, IFS_DHCP, 0, IFS_END);
         printf("Network relinquished; re-acquiring in 3 secs...\n");
         ip_print_ifs();
         st = SEC_TIMER + 3;
         while (SEC_TIMER < st);
         //if (!(status = dhcp_acquire())) {
         if (!(status = ifconfig(IF_DEFAULT, IFS_DHCP, 1, IFS_END))) {
            printf("Lease re-acquired\n");
            print_results();
         }
         else if (status == 1) {
            printf("Hmmm... lease re-acquired with DIFFERENT IP address\n");
            print_results();
         }
         else {
            printf("Whoops!  Lost network.  DHCP server probably down.\n");
            exit(79);
         }
      }

      // When we first get the boot file, print its length.  _bootpdone is
      // a global variable which gets set to 1 if the bootfile has been
      // downloaded, 2 if there was no bootfile specified, or
      // 0 if bootfile status not yet known.
      if (!pboot && _bootpdone) {
         pboot = true;
         if (_bootpdone == 2)
            printf("No network boot file configured by server\n");
         else {
            printf("Network boot file:\n");
            if (_bootperror && _bootperror != -5)
               printf("  Error code %d: %s\n", _bootperror,
                 _bootperror == -1 ? "Server denied access" :
                 _bootperror == -2 ? "Could not contact server" :
                 _bootperror == -3 ? "Timed out" :
                   "unknown error"
                 );
            else {
               printf("  Length = %u\n", _bootpsize);
               if (_bootperror == -5)
                  printf("  File was truncated\n");
               putback = true;
            }
         }
      }

      // Once we have the boot file, echo it back to the server.  Sometimes, for
      // a length which is not an exact multiple of 512, an error condition will
      // be returned.  This happens when the server is non-RFC compliant and
      // does not wait around to ACK the last packet.  It's not our fault!
      if (putback) {
         putback = false;
         ts.state = 1;   // Write
         ts.buf_addr = _bootpdata;
         ts.buf_len = _bootpsize;
         ts.my_tid = 0;
         ts.sock = NULL;   // use DHCP one
         ts.rem_ip = 0;      // use bootp server
         ts.mode = TFTP_MODE_OCTET;
         strcpy(ts.file, "/tftpboot/echo");
         printf("Sending boot file back as %s\n", ts.file);

         // This uses the non-blocking TFTP functions, but in a blocking
         // manner.  It would be easier to use tftp_exec(), but this
         // doesn't return the server error message.
         if (!tftp_init(&ts)) {
            while ((status = tftp_tick(&ts)) > 0);   // Loop until complete
            if (!status)
               printf("Upload completed\n");
            else {
               printf("Upload failed: code %d\n", status);
               if (status == -1)
                  printf("  Message from server: %s\n", ts.file);
            }
         }
         else
            printf("Error: could not use dchp socket for tftp\n");

         // Now we do it again, using tftp_exec().
         //bflen = _bootpsize;
         //status = tftp_exec(1,_bootpdata,&bflen,1,NULL,"/tftpboot/echo2",NULL);
         //printf("echo2 uploaded: status = %d\n", status);
      }
   }
}
Pisałem o tym już wcześniej i tylko dla przypomnienia:

Kod: Zaznacz cały

#define TCPCONFIG      5
Ten zapis konfiguruje adresację do oczekiwanego wariantu (związanego z serwisem DHCP). W roli matki chrzestnej występuje mój domowy serwer DHCP, a uroczyście nadane imię jest następujące:
Starting network (max wait 6 seconds)...
Lease obtained
Network Parameters:
My IP Address = C0A8006F [192.168.0.111]
Netmask = FFFFFF00 [255.255.255.0]
Remaining lease = 86398 (sec)
Renew lease in 43198 (sec)
DHCP server = C0A800FE [192.168.0.254]
Boot server = 00000000
Timezone (fallback only) = 0h
DNS server #1 = C0A800FE [192.168.0.254]
No network boot file configured by server

No i nie da się ukryć, wszystko się zgadza. Króliczy procek dogadał się z domowym serwerem DHCP, co potwierdza świadek ping.
rab09_ilu01.png
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse


Wróć do „Inne mikroklocki, również peryferyjne”

Kto jest online

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