logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Jak napisać prosty program w C do obsługi portu LPT w Linux?

piroaa 10 Paź 2007 17:22 10393 16
REKLAMA
  • #1 4365976
    piroaa
    Poziom 11  
    Posty: 81
    Ocena: 2
    Potrzebuje prostego programu napisanego w C do obsługi portu LPT w systemie linux,

    pogrzebałem trochę w internecie poczytałem poradniki o C i tak oto powstał konsolowy program do obsługi tego portu :
    
        2 #include <stdio.h>
          3 #include <string.h>
          4 #include <sys/io.h>
          5 #include <sys/perm.h>
          6
          7 #define BASEPORT 0x378
          8
          9 int main(int liczba, char *parametr[])
         10 {
         11 //ioperm otwiera port
         12         ioperm(BASEPORT,1,1);
         13    // int i;
         14    // for (i = 0; i < liczba; i++)
         15    // printf("Argument nr %d: %s\n", i, parametr[i]);
         16         int wynik = 2;
         17 // PISZ
         18         wynik = strcmp(parametr[1],"-pisz");
         19         if (wynik == 0){
         20         wynik = atoi(parametr[2]); //atoi() -stringa na intrger
         21         printf("pisz gotowe \n");
         22         printf("wynik mamy %i \n",wynik);
         23         outb(wynik,BASEPORT);
         24         }
         25 //CZYTAJ
         26         wynik = strcmp(parametr[1],"-czytaj");
         27         if (wynik == 0) {
         28
         29         wynik = inb(BASEPORT);
         30         printf("stanportu %i \n",wynik);
         31         }
         32 //PIN
         33         wynik = strcmp(parametr[1],"-pin");
         34         if (wynik ==0){
         35
         36         printf("Wywołano z -pin \n");
         37         }
         38
         39         wynik = strcmp(parametr[1],"-h");
         40         if (wynik == 0) {
         41         printf("lptset - ustawia i odczytuje wartości na porcie LPT \n -pisz xxx pozwala włączyć poszczegóe piny w p                orcie LPT\n paramet powinien być podany w formie dziesiętnej.\n\n -czytaj pozwala odczytać stany pinów wynik                podawawny w formie dziesiętnej\n\n -pin podaje stan portów tylko do odczytu\n");
         42         }
         43     return 0;
         44 }

    program po skompilowaniu gcc działa bez zarzutu , jednym problemem jest to że nie mogę nigdzie wylaleść sposobu do odczytu z pinów od 11 do 15 (z pominięcien 14) są to linie tylko do odczytu stan na nich można zmienić zwierają je do masy, niestety żaden znaleziony poradnik wynaleziony przeze mnie , nie traktuje o tym jak odczytać stany tych właśnie portów .
    Jeśli ktoś wie jak rozwiązać ten problem to będę wdzięczny za pomoc.
    PS.
    Pragnę zaznaczyć że NIE programuję w C, dlatego prosił bym o w mire łopatologiczną odpowiedź.

    Z góry dziękuje za okazaną pomoc.
  • REKLAMA
  • #2 4367594
    piotrkopec
    Poziom 17  
    Posty: 189
    Pomógł: 24
    Ocena: 2
    Dla 'lpt' dostępne są jeszcze dwa dodatkowe ośmiobitowe rejestry pod adresami 'BASEPORT + 1' i 'BASEPORT + 2'. Odczytujesz je tak samo( możesz również pisać na sygnały wyjściowe) jak 'BASEPORT' czyli
    wynik_1 = inb(BASEPORT + 1);
    wynik_2 = inb(BASEPORT + 2); 

    znaczenie bitów rejestrów:
    !przy pinach z '~' stan napięcia na pinie jest negacją stanu logicznego odpowiadającego bitu!
    Cytat:
    dla 'BASEPORT + 1':
    BIT7 - ~PIN11
    BIT6 - PIN10
    BIT5 - PIN12
    BIT4 - PIN13
    BIT3 - PIN15
    BIT2,BIT1,BIT0 - NIC NIE ZNACZĄ

    Cytat:
    dla 'BASEPORT + 2':
    BIT7,BIT6,BIT5 - NIC NIE ZNACZĄ
    BIT4 - generowanie IRQ( 1 włączone, 0 wyłączone)
    BIT3 - ~PIN17
    BIT2 - PIN16
    BIT1 - ~PIN14
    BIT0 - ~PIN1

    w 'C' aby określić stan konkretnego bitu w bajcie( i większych słowach) możesz nałożyć na odczytany bajt maskę( bitowe '&' czyli 'AND'). Odrzucisz w ten sposób nieinteresujące Cię bity. Maskę uzyskasz przez przesunięcie w lewo( operacja '<<') '1'ynki na pozycję interesującego Cię bitu.
    I tak aby sprawdzić stan PIN10( czyli BIT6 z 'BASEPORT + 1') wykonasz:
    unsigned char wynik_1 = inb(BASEPORT + 1); // odczytujesz bajt
    bool bit_6 = wynik & ( 1 << 6 );   // nałożenie maski '01000000b' na bajcior
    

    lub trochę inaczej przesuwając bajt w prawo tak aby interesujący bit znalazł się na pozycji bit0( operacja '>>') i nakładając na przesunięty bajt maskującej '1'ynki czyli:
    bool bit_6 = (wynik_1 >> 6) & 1;

    aby poprawnie odczytać stan napięć 'odwróconych' pinów takich jak '~PIN11' musisz dodatkowo zanegować wartość odpowiadającego mu bitu:
    bool pin_11 = ! bit_7;

    i wyświetlenie
     printf( "stan pin'u 11 to %i \n", pin_11);

    pozdrawiam
  • #3 4368030
    piroaa
    Poziom 11  
    Posty: 81
    Ocena: 2
    coś chyba nie tak zrozumiałem bo po przeróbce pinu na :

         33         wynik = strcmp(parametr[1],"-pin");
         34         if (wynik ==0){
         35 
         36         wynik = inb(BASEPORT+1);       
         37         printf("Stan portu do odczytu : %i \n",wynik);
         38         }
    


    i próbie uruchomienia programu z przełącznikiem -pin dostaje komunikat :
    Segmentation fault (core dumped)

    reszta przełączników działa dalej bez zarzutu.

    Dodam jeszcze że po twojej odpowiedz za która dziękuje przeszukałem zasoby sieciowe pod kątem zapytania BASEPORT+1 i natrafiłem na: http://uvasux.googlepages.com/interfacingtheparallelport
    i tam również wykorzystują tę metodę do odczytu stanów portu.
  • #4 4369083
    piotrkopec
    Poziom 17  
    Posty: 189
    Pomógł: 24
    Ocena: 2
    Bam... zapomniałem :)
    z kodu który przytoczyłeś:
         11 //ioperm otwiera port
         12         ioperm(BASEPORT,1,1);

    do używania portów '+1' i '+2' musisz mieć również zezwolenie. Uzyskasz je przez powtórzenie 'ioperm(...)' dla 'BASEPORT+1' i '+2' lub zmodyfikowanie ilości bajtów objętych zezwoleniem czyli zgodnie z deklaracją ioperm:
    int ioperm(unsigned long from, unsigned long num, int turn_on);

    będzie to:
    ioperm( BASEPORT, 3, 1);
  • #5 4369433
    piroaa
    Poziom 11  
    Posty: 81
    Ocena: 2
    Teraz wszystko działa pieknie.
    Wielkie dzięki za pomoc sam nigdy bym do tego nie doszedł.
    A swoja drogą dziwna sprawa z tym ioperm() myślałem że skoro daje dostęp do portu to do całego a nie tylko do wybranych pinów.

    Dla zainteresowanych podaje finalną wersję kodu :
    
           1 //lptset.c
          2 #include <stdio.h>
          3 #include <string.h>
          4 #include <sys/io.h>
          5 #include <sys/perm.h>
          6 
          7 #define BASEPORT 0x378
          8 
          9 int main(int liczba, char *parametr[])
         10 {
         11 //ioperm otwiera port
         12         ioperm(BASEPORT,1,1);
         13         ioperm(BASEPORT+1,1,1);
         14         int wynik = 2;
         15 
         16 // PISZ
         17         wynik = strcmp(parametr[1],"-pisz");
         18         if (wynik == 0){
         19         wynik = atoi(parametr[2]); //atoi() -stringa na intrger
         20         printf("Port ustawiono na : %i \n",wynik);
         21         outb(wynik,BASEPORT);
         22         printf("pisz gotowe \n");
         23         return 0;
         24         }
         25 //CZYTAJ
         26         wynik = strcmp(parametr[1],"-czytaj");
         27         if (wynik == 0) {
         28 
         29         wynik = inb(BASEPORT);
         30         printf("stan portu : %d \n",wynik);
         31         return 0;
         32         }
         33 //PIN
         34         wynik = strcmp(parametr[1],"-pin");
         35         if (wynik ==0){
         36 
         37         wynik = inb(BASEPORT+1);
         38         printf("Stan portu do odczytu : %d \n",wynik);
         39         return 0;
         40         }
         41 
         42         wynik = strcmp(parametr[1],"-h");
         43         if (wynik == 0 | wynik != 0 ) {
         44         printf("\n lptset - ustawia i odczytuje wartości na porcie LPT \n\n -pisz xxx pozwala włączyć po        szczegóe piny w porcie LPT\n           paramet powinien być podany w formie dziesiętnej.\n -czytaj   poz        wala odczytać stany pinów wynik podawawny w formie dziesiętnej\n -pin      podaje stan portów tylko do o        dczytu\n");
         45         }
         46     return 0;
         47 }
        
    

    DO kompilacji wystarczy gcc.
    Dla leniwych załączam wersję juz skompilowaną.
    !!!UWAGA!!!
    Jak już pisałem NIE jestem programistą C i z racji tego program może zawierać błędy które w konsekwencji mogą doprowadzić do zniszczenia portu LPT , płyty głównej , pożarów powodzi i innych niepożądanych kataklizmów ...
    U mnie nic takiego się nie zdarzyło ale zawsze pisze się takie rzeczy o auto odpowiedzialności na wszelki wypadek ...

    No i najważniejsze wielkie podziękowanie dla użytkownika piotrkopec za poświęcony czas i w ogóle za wszystko bez niego program nigdy by nie powstał.

    Pozdrawiam serdecznie i jeszcze raz dziękuje za pomoc.
    Załączniki:
    • lptset.exe (7.74 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • REKLAMA
  • #6 4412458
    Alana
    Poziom 37  
    Posty: 3146
    Pomógł: 361
    Ocena: 245
    jestes pewny tego kodu?
    wlasnie to skompilowalam i segmentation fault
    mam debiana, gcc 4.1.2 kernel 2.6.14

    edyta numer n+1:

    w programie jest bug, wywolanie bez parametrow wywala program w kosmos

    poprawiony kod:
    
     //lptset.c
    #include <stdio.h>
    #include <string.h>
    #include <sys/io.h>
    #include <sys/perm.h>
    
    #define BASEPORT 0x378
    void help(void);
    
    int main(int liczba, char *parametr[])
    {
    if (liczba > 1)
      {
      //ioperm otwiera port
      ioperm(BASEPORT,1,1); //rejestr danych
      ioperm(BASEPORT+1,1,1); //rejestr wejscia
      ioperm(BASEPORT+2,1,1); //rejestr statusu
      int wynik = 2;
      
      // PISZ
      wynik = strcmp(parametr[1],"-pisz");
      if (wynik == 0)
        {
        if (liczba > 2)
          {
          wynik = atoi(parametr[2]); //atoi() -stringa na intrger
          printf("Port danych ustawiono na : %Xh \n",wynik);
          outb(wynik,BASEPORT);
          printf("gotowe \n");
          return 0;
          }
        else
          {
          printf("BLAD!!\n");
          return 0;
          }
        }
        // PISZ starus
        wynik = strcmp(parametr[1],"-piszs");
        if (wynik == 0)
        {
        if (liczba > 2)
          {
          wynik = atoi(parametr[2]); //atoi() -stringa na intrger
          printf("Port statusu ustawiono na : %Xh\n",wynik);
          outb(wynik,BASEPORT+2);
          printf("gotowe \n");
          return 0;
          }
        else
          {
          printf("BLAD!!\n");
          return 0;
          }
        }
        //CZYTAJ
        wynik = strcmp(parametr[1],"-czytaj");
        if (wynik == 0)
          {
          wynik = inb(BASEPORT);
          printf("stan portu danych: %Xh\n",wynik);
          return 0;
          }
        //PIN
        wynik = strcmp(parametr[1],"-pin");
        if (wynik ==0)
          {
          wynik = inb(BASEPORT+1);
          printf("Stan portu do odczytu : %Xh\n",wynik);
          wynik = inb(BASEPORT+2);
          printf("Stan portu sterujacego : %Xh\n",wynik);
          return 0;
          }
        //help
        wynik = strcmp(parametr[1],"-h");
        if (wynik == 0 | wynik != 0 )
          {
          help();
          return 0;
          }
      }
    else help();
    return 0;
    }
    
    void help(void)
    {
    printf("\n lptset - ustawia i odczytuje wartości na porcie LPT \n\n");
    printf("-pisz xxx pozwala włączyć poszczegóe piny w porcie LPT\n");
    printf("-piszs xxx pozwala włączyć poszczegóe piny w porcie statusu LPT\n");
    printf("paramet powinien być podany w formie dziesiętnej.\n");
    printf("-czytaj   pozwala odczytać stany pinów\n");
    printf("-pin      podaje stan portów tylko do odczytu\n");
    printf("PROGRAM DZIALA TYLKO Z ROOT-a\n");
    }

    ze swojej strony dodalam odczyt i zapis rejestru statusu z pod adresu BAZOWY + 2 i wyswietlanie liczb jako HEX

    btw 5 punktow za orginalny kod, zaoszczedziles mi sporo pracy
  • REKLAMA
  • #8 5871289
    CyberDuck
    Poziom 12  
    Posty: 45
    Ocena: 2
    Jestem winien podziekowania Alana.
    Dzieki niej mam pakiet ktorym sie moge podzielic :
    zalacznik

    W pakiecie praktycznie jest wszystko.
    Komendy :
    lptset -piszs 32 ustawia port lpt w stan wejsc i wtedy mozna czytac
    to co podamy na wejscia d0 - d7.
    lptset -czytaj podaje wartosc jaka jest podana na wejscia d0 - d7
    lub odczytuje jaka jest ustawiona wartosc poprzez :
    lptset -pisz x gdzie x to liczba z zakresu 0 - 255.
    Przeliczajac to na binarny zapis daje odpowiednie ustawienia na
    wyjsciach d0 - d7.
    lptset -piszs 0 ustawia port lpt w stan wyjscia.

    Procedurka dziala pod linux i praktycznie zostala wyprobowana
    pod debian oraz pod systemem serwerowym NND.

    Zeby calosc zadzialala poprawnie to wczesniej w bios komputera
    nalezy ustawic port lpt w mod epp lub bidirectional.
    Procedurke umieszcza sie w dowolnym katalogu i jesli jest
    umieszczony w innym katalogu niz domyslny systemowy to nalezy
    dodac wczesniej sciezke do tej procedurki np :
    /home/pliki/lptset -pisz 20

    Jesli niebedzie mimo tych zabiegow dzialac to nalezy ustawic
    odpowiednie uprawnienia :
    chmod +s lptset .
    Przed tym ostatnim jednak trzeba sie dobrze zastanowic poniewaz
    daje to mozliwosc uzycia procedury przez dowolna osobe jesli
    ma tylko dostep do systemu. Chocby poprzez wlamanie.
    Mozna oczywiscie isc dalej i napisac sobie skrypt w php :
    $wystaw = '15';
    shell_exec("lptset -pisz $wystaw");
    i na wyjsciu lpt pojawi sie odpowiedni stan.
    Mozna tez oczywiscie czytac :
    $stan = shell_exec(lptset -czytaj);
    i w zmiennej mamy juz wartosc jaka jest ustawiona na porcie lpt.

    Mysle, ze ten opis zamyka wszelkie dyskusje na ten temat.
    Przydalaby sie tez instrukcja zmieniajaca pojedyncze bity, ale tego jest
    pelno w necie :
    pobierz zalacznik
    zgas XXX powoduje ustawienie wybranych bitow w stan 0
    np :
    zgas 1 5 8
    Spowoduje ustawienie bitow 0, 4, 7 na porcie lpt w stan 0. Pozostale
    pozostaja bez zmian.
    zgas 0
    spowoduje ustawienie wszystkich bitow w stan 0
    zapal XXX powoduje ustawienie bitow w stan 1 na dowolnej pozycji:
    zapal 3 4 6
    spowoduje ustawienie w stan 1 bitow 2, 3, 5.
  • REKLAMA
  • #10 5937005
    CyberDuck
    Poziom 12  
    Posty: 45
    Ocena: 2
    Yyyy nierozumiem :) Do jakiego drugiego ?
    Zalacznik jest caly czas aktywny i bede go utrzymywac
    dlygo :)
  • #11 5937387
    Alana
    Poziom 37  
    Posty: 3146
    Pomógł: 361
    Ocena: 245
    Tak ale pamietasz co ci pisalam na temat kompilowania - to nie zawsze zadziala wiec lepiej miec kod zrodlowy programu i skompilowac sobie samemu. Zalaczniki sa jak najbardziej OK.
  • #12 5937938
    CyberDuck
    Poziom 12  
    Posty: 45
    Ocena: 2
    Przeciez kod zrodlowy jest wyzej :)
    Jesli ktos potrafi kompilowac program do kodu
    wynikowego wystarczy usunac zbedne komunikaty, albo
    wrecz bez usuwania komunikatow skorzystac z komendy.
    Ja uzylem do wykonywania komend PHP. To co zostanie
    wyswietlone na stronie czy tez nie zalezy wylacznie od
    programisty.
  • #14 5938171
    CyberDuck
    Poziom 12  
    Posty: 45
    Ocena: 2
    Aaaaa o te kody chodzi :D
    A to nie ma problem :P
    Akurat z tymi kodami mialem najmniej problemow bo byly jako juz
    gotowe dzialajace programy. Wyprobowalem pod NND i zadzialaly.
    Mysle, ze pod kazdym innym systemem Linuxowym spokojnie
    zadzialaja.
    Wziolem je stad :
    http://viater.one.pl/pub2/nnd/resetery/
  • #15 6929863
    CyberDuck
    Poziom 12  
    Posty: 45
    Ocena: 2
    Od tego czasu sie troszke zmienilo i wielokrotnie
    pozmienialem nieco w kodzie php.
    Teraz to mozna ogladac sobie tutja na zywo :
    www.bluelan.pl/admin/1.php haslo demo.
  • #16 6931325
    piotrkopec
    Poziom 17  
    Posty: 189
    Pomógł: 24
    Ocena: 2
    Bardzo przyjemne demo.
    Ale myślę, że lepszy efekt dałoby podpięcie się pod instalację elektryczną w bloku ;)
    Kamerka z zegarkiem binarnym na wieżowcu miałaby pewnie niezłą oglądalność.
    Pozdrawiam :)
  • #17 6931753
    CyberDuck
    Poziom 12  
    Posty: 45
    Ocena: 2
    Moze i tak, ale glownie chodzilo tylko o pokazanie co
    mozna i jak mozna. Mozliwosci urzadzenia mozna zwielokrotnic.
    Dzisiaj podpiecie do tego np mikrokontrolera i zwiekszenie
    ilosci sterowanych urzadzen to juz zaden problem.
    Kiedys nawet chcialem cos takiego zrobic z mozliwoscia
    sterowania kamerka, ale w sumie komu mialoby to sluzyc ? ...

Podsumowanie tematu

✨ Dyskusja dotyczyła stworzenia prostego programu w języku C do obsługi portu LPT (równoległego) w systemie Linux. Omówiono wykorzystanie funkcji ioperm() do uzyskania dostępu do portu i jego rejestrów (BASEPORT 0x378 oraz BASEPORT+1 i BASEPORT+2), które odpowiadają za dane, status i sygnały wyjściowe. Podkreślono konieczność przyznania uprawnień do wszystkich trzech rejestrów, aby uniknąć błędów typu segmentation fault. Zaprezentowano metody odczytu i zapisu bitów portu LPT za pomocą funkcji inb() i maskowania bitowego. Wskazano na problem z wywołaniem programu bez parametrów i zaproponowano poprawiony kod z obsługą takiego przypadku. Wskazano także na bibliotekę parapin jako alternatywne narzędzie do obsługi portu LPT w Linuksie. W dalszej części dyskusji udostępniono gotowy pakiet narzędziowy lptset, umożliwiający ustawianie portu w tryb wejścia/wyjścia oraz odczyt i zapis wartości na liniach D0-D7. Zwrócono uwagę na konieczność ustawienia portu LPT w BIOS-ie w tryb EPP lub bidirectional dla poprawnej pracy. Wspomniano o praktycznym zastosowaniu i testach pod Debianem oraz systemem serwerowym NND. Dyskusja zawierała także linki do źródeł i przykładów kodu oraz sugestie dotyczące dalszego rozwoju i integracji z mikrokontrolerami.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA