Thread View: pl.comp.os.linux.programowanie
7 messages
7 total messages
Started by spryciarzsprytny7
Tue, 10 Jul 2018 16:54
Jak skutecznie odczytać wolne miejsce w buforze nadawczym portu szeregowego?
Author: spryciarzsprytny7
Date: Tue, 10 Jul 2018 16:54
Date: Tue, 10 Jul 2018 16:54
18 lines
2394 bytes
2394 bytes
Witam Jak już wspominałem piszę obsługę portu szeregowego. Dzięki waszej pomocy zrozumiałem działanie funkcji select/pselect, jednak mam też inny problem przy obsłudze tego portu. Tym problemem jest zbyt szybkie wysyłanie danych na ten port przez co gubione są pakiety. By dowiedzieć się ile mogę zapisać funkcją write() używam funkcji: ioctl(mPortDescriptor, TIOCOUTQ, &lFreeSpaceSize); Jednak wygląda na to, że zawsze ona zwraca 0 - nawet pomimo braku zapisów do portu np. przy pernamentnym pomijaniu wysyłania: if(lFreeSpaceSize <= 0) // we must wait for serial port Jutro jeszcze raz sprawdzę działanie tej funkcji z poprawnym ustawianiem tablic deskryptorów dla pselect. Jednak już teraz mogę spytać: Czy to prawidłowe podejście by odczytywać wielkość dostępnego bufora wyjściowego portu szeregowego funkcją ioctl z parametrem TIOCOUTQ ? Jeśli nie to mam dodatkowe pytanie: Jaką funkcją należy odczytywać wielkość bufora wyjściowego portu szeregowego w Linux-ie? z góry dzięki i pozdro Jacek
Re: Jak skutecznie odczytać wolne miejsce w buforze nadawczym portu szeregowego?
Author: spryciarzsprytny7
Date: Wed, 11 Jul 2018 09:07
Date: Wed, 11 Jul 2018 09:07
5 lines
2255 bytes
2255 bytes
Nie wiem czy dobrze... ale... u mmie działa, więc: dla potomnych: Na podstawie: https://stackoverflow.com/questions/13181040/how-can-i-determine-the-amount-of-write-output-buffer-space-left-on-a-linux-seri Port szeregowy jest urządzeniem znakowym a nie blokowym. Dlatego nie istnieje w nim pojęcie bufora. Tylko nie wiedzieć czemu można odczytać wielkość danych oczekujących do odczytu. Jednak nie można sprawdzić ile danych można zapisać do bufora wyjściowego. Dlatego zrobiłem tak, że zapisuję do portu szeregowego 1 bajt i wywołuję pselect czekając na gotowość portu szeregowego do zapisu. I to działa wygląda na to, że wszystkie dane są poprawnie wysyłane (nawet jak jest ich więcej niż 4KB - czyli więcej niż bufor portu szeregowego w Linux-ie).
Re: Jak skutecznie odczytać wolne miejsce w buforze nadawczym portu szeregowego?
Author: Adam Wysocki
Date: Wed, 11 Jul 2018 12:46
Date: Wed, 11 Jul 2018 12:46
27 lines
2104 bytes
2104 bytes
spryciarzsprytny7@gmail.com wrote: > Jaką funkcją należy odczytywać wielkość bufora wyjściowego portu > szeregowego w Linux-ie? Nie odczytywać. 1. Zapisz coś do własnej, wewnętrznej kolejki 2. Wywołaj select() (pytaj o writability tylko gdy kolejka jest niepusta) 3. Jak select() zwróci writability to wyślij całą kolejkę do write() (ale nie więcej, niż SSIZE_MAX bajtów) 4. write() zwróci, ile faktycznie zapisało (lub -1 i ustawi errno) 5. Zdejmij to, co zapisało write(), z kolejki 6. Skok do punktu 2 Jeśli write() zwróciło tyle bajtów, ile wysłałeś, a bajty są gubione w urządzeniu odbiorczym, to raczej sprawdziłbym, czy urządzenie odbiorcze nie ma problemu z zerowym odstępem między bajtami. Spotkałem się z urządzeniami, które miały taki problem i trzeba było wysyłać do nich znak po znaku z doświadczalnie dobranym odstępem. Generalnie obsługę najłatwiej sprawdzisz robiąc pętlę (zwierając TXD i RXD na porcie) i czytając to, co wysłałeś. -- [ Email: a@b a=grp b=chmurka.net ] [ Web: http://www.chmurka.net/ ]
Re: Jak skutecznie odczytać wolne miejsce w buforze nadawczym portu szeregowego?
Author: spryciarzsprytny7
Date: Wed, 11 Jul 2018 18:05
Date: Wed, 11 Jul 2018 18:05
12 lines
3232 bytes
3232 bytes
Dzięki za odpowiedź. Skomentuję twoją odpowiedź, bo mam wątpliwości. > 3. Jak select() zwróci writability to wyślij całą kolejkę do write() > (ale nie więcej, niż SSIZE_MAX bajtów) Bufor portu szeregowego w Linux-e to 4KB. Przynajmniej bufor wejściowy tyle ma... Natomiast SSIZE_MAX to 9223372036854775807 (w Kubuntu 18.10 jaki mam pod ręką - podejrzewam, że na Raspbianie jest podobnie bo to też 64 bitowy system - mogę to jutro sprawdzić). Tak więc ZCW te twoje zastrzeżenie w nawiasie jest bez sensu, bo SSIZE_MAX jest dużo większa od całej pamięci operacyjnej... Poza tym nawet gdyby założyć, że SSIZE_MAX ma wielkość bufora to i tak nie o to mi chodzi, bo ja chcę wykorzystać bufor Linux-a do ciągłej transmisji (w tym celu też robię obsługę zapisu i odczytu w 2 wątkach). Bardzo mi zależy na tym, by zrobić obsługę portu szeregowego porządnie i by byłą uniwersalna i wydajna. Tak by był sens użycia jej do innych projektów... Póki tego nie wyjaśnisz, to nie będę niczego zmieniał, bo jak pisałem, zapis po jednym bajcie z uprzednim sprawdzeniem pselect działa bez zarzutu... W sumie to nie wiem co widzisz w tym złego (w zapisie bajt po bajcie), skro jest powiedziane (przez inne guru - link w mojej poprzedniej wypowiedzi), że w Linux-ie port szeregowy to urządzenie znakowe, a nie blokowe - przez to nie ma buforów i zapis i odczyt odbywa się po jednym znaku (tak działa też klawiatura i mysz). W sumie trochę tego nie jarzę, bo można sprawdzić ile danych jest do odczytu, a nie wiadomo ile można wysłać...
Re: Jak skutecznie odczytać wolne miejsce w buforze nadawczym portu szeregowego?
Author: spryciarzsprytny7
Date: Wed, 11 Jul 2018 18:17
Date: Wed, 11 Jul 2018 18:17
6 lines
2208 bytes
2208 bytes
> Dlatego zrobiłem tak, że zapisuję do portu szeregowego 1 bajt i wywołuję pselect czekając na gotowość portu szeregowego do zapisu. Oczywiście robię odwrotnie: 1. wywołuję pselect z parametrem writefds który podaję jako strukturę fd_set z moim deskryptorem protu szeregowego. Ta funkcja czeka na gotowość portu do zapisu. 2. wysyłam pojedynczy bajt (z bufora wyjściowego mojej aplikacji) do portu szeregowego zwykłą funkcją write 3. przechodzę do punktu 1 dopóki mam dane w buforze (wyjściowym mojej aplikacji)
Re: Jak skutecznie odczytać wolne miejsce w buforze nadawczym portu szeregowego?
Author: Adam Wysocki
Date: Wed, 11 Jul 2018 19:45
Date: Wed, 11 Jul 2018 19:45
66 lines
3864 bytes
3864 bytes
spryciarzsprytny7@gmail.com wrote: >> 3. Jak select() zwróci writability to wyślij całą kolejkę do write() >> (ale nie więcej, niż SSIZE_MAX bajtów) > > Bufor portu szeregowego w Linux-e to 4KB. Przynajmniej bufor wejściowy > tyle ma... Natomiast SSIZE_MAX to 9223372036854775807 (w Kubuntu 18.10 > jaki mam pod ręką - podejrzewam, że na Raspbianie jest podobnie bo to > też 64 bitowy system - mogę to jutro sprawdzić). Tak więc ZCW te twoje > zastrzeżenie w nawiasie jest bez sensu, bo SSIZE_MAX jest dużo większa > od całej pamięci operacyjnej... Bo to 64-bitowy system. Na 32-bitowym masz 2GB. POSIX gwarantuje 32kB. Sam wysyłam rozsądnie niewielkimi porcjami (zwykle do 4kB lub PIPE_BUF), co by write() za długo nie blokowało kopiując dane z userspace. > W sumie to nie wiem co widzisz w tym złego (w zapisie bajt po bajcie), Zapis bajt po bajcie jest niewydajny. Każdy zapis powoduje przełączenie kontekstu i zwiększa overhead. Zrób prosty benchmark, nawet na dd. [gof@pi ~]$ dd if=/dev/zero of=/dev/null bs=1 count=10000000 10000000+0 records in 10000000+0 records out 10000000 bytes (10 MB) copied, 12.9187 s, 774 kB/s [gof@pi ~]$ dd if=/dev/zero of=/dev/null bs=100 count=100000 100000+0 records in 100000+0 records out 10000000 bytes (10 MB) copied, 0.209594 s, 47.7 MB/s [gof@pi ~]$ dd if=/dev/zero of=/dev/null bs=1000 count=10000 10000+0 records in 10000+0 records out 10000000 bytes (10 MB) copied, 0.0355727 s, 281 MB/s [gof@pi ~]$ dd if=/dev/zero of=/dev/null bs=10000 count=1000 1000+0 records in 1000+0 records out 10000000 bytes (10 MB) copied, 0.00900733 s, 1.1 GB/s Linus kiedyś podsumował to w swoim stylu: https://lkml.org/lkml/2012/7/6/495 > skro jest powiedziane (przez inne guru - link w mojej poprzedniej > wypowiedzi), że w Linux-ie port szeregowy to urządzenie znakowe, a nie > blokowe - przez to nie ma buforów i zapis i odczyt odbywa się po jednym > znaku (tak działa też klawiatura i mysz). Urządzenie znakowe oznacza, że podstawową jednostką transmisji jest w nim bajt a nie, że odczyt i zapis odbywają się po jednym bajcie. Większość (jeśli nie każdy) układów uartopodobnych ma jakąś kolejkę / bufor, żeby móc wysyłać następny bajt zaraz po tym, jak wyślą poprzedni. > W sumie trochę tego nie jarzę, bo można sprawdzić ile danych jest do > odczytu, a nie wiadomo ile można wysłać... Nie spotkałem się z sytuacją, w której potrzebowałbym wiedzieć, ile mogę wysłać danych. Do czego jest Ci taka informacja? Masz do wysłania tyle, ile masz, więc wysyłasz tyle, ile możesz (na ile write() pozwoli). -- [ Email: a@b a=grp b=chmurka.net ] [ Web: http://www.chmurka.net/ ]
Re: Jak skutecznie odczytać wolne miejsce w buforze nadawczym portu szeregowego?
Author: szykcech
Date: Fri, 13 Jul 2018 18:11
Date: Fri, 13 Jul 2018 18:11
13 lines
2461 bytes
2461 bytes
Sprawdziłem i potwierdzam: By zapisać N bajtów z bufora Buff do portu szeregowego trzeba: 1. Utorzyć zmienną pomocniczą int lWriten: 2. W pętli: 3. Wstawić deskryptor(y) portu do struktury fd_set makrem FD_SET 4. czekać na gotowość do zapisu portu szeregowego pselect/select (writefds) 5. zapisaywać tyle ile się da czyli lWiten += write(deskryptor, Buff, N - lWriten) 6. Jeśli nie N == lWriten skocz do 3. Komentarz: Oczywiście to tylko skrót tego co trzeba zrobić. Bo w normalnej aplikacji trzeba pomyśleć o obsłudze błędów, sygnałów od systemu, żądania przerwania pracy (np. przy zamykaniu programu)... Dlatego: lWiten += write(deskryptor, Buff, N - lWriten) Na pewno nie jest dobrym pomysłem, bo nie uwzględnia możliwości zwrócenia -1 przez write(). Dlatego tu trzeba się posłużyć zmienną pomocniczą.
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads