-
1. Data: 2022-09-24 17:58:49
Temat: lwIP - odbieranie danych przez TCP
Od: Atlantis <m...@w...pl>
Chciałem ostatnio popchnąć trochę do przodu jeden ze swoich poprzednich
projektów - sprzętowe radio internetowe o którym pisałem już wcześniej,
tylko tym razem w wersji ze zaktualizowaną częścią hardware'ową.
Poprzednia wersja była tworzona na PIC32, teraz powoli chciałem
przenieść go na STM32.
Większość softu właściwie już przeniosłem, teraz zostało najważniejsze -
przeportowanie samej aplikacji odpowiedzialnej za odtwarzanie streamu z
Internetu. W przypadku biblioteki MLA na PIC32 było to relatywnie
proste. Socket sieciowy dysponuje buforem FIFO o zdefiniowanej
pojemności - do niego trafiają dane przychodzące z serwera. Dane te
pobieram i ładuję do bufora audio. Robię to jednak dopiero wtedy, gdy
sterownik układu VS1003 stwierdzi, że dane są potrzebne.
W przypadku PIC32 było to relatywnie proste. Miałem kilka funkcji:
- TCPIsGetReady() - zwracała liczbę bajtów w buforze
- TCPGetArray() - funkcja zapisywała pod podany adres w pamięci
określoną maksymalną liczbę bajtów z bufora. Zwracała liczbę bajtów,
które w rzeczywistości udało się pobrać.
Sprawa była prosta - wystarczyło albo pobrać wszystkie dostępne dane,
ale (jeśli było ich za dużo) tylko tyle, żeby wypełnić dostępne miejsce.
W tym drugim przypadku nadwyżka pozostawała w buforze gniazda sieciowego
i była sukcesywnie uzupełniania o kolejne przychodzące dane, które
mogłem pobrać wtedy, gdy znów były potrzebne.
Widzę, że w przypadku lwIP (RAW API) sprawa nie jest już tak prosta.
Zamiast tego muszę zarejestrować callback, który jest wołany za każdym
razem, gdy przyjdą nowe dane. Callback otrzymuje w jednym z parametrów
wskaźnik do struct ptr, w której mam m.in.
- void* paylod
- int len
- int tot_len
- struct pbuf* next
Istnieje więc możliwość, że wszystko co będę musiał zrobić to pobranie
skopiowanie len bajtów spod adresu na który wskazuje payload. Istnieje
jednak szansa, że danych jest więcej - wtedy tot_len > len i kolejnej
porcji danych trzeba szukać w kolejnej strukturze, na którą wskazuje
wskaźnik next.
Jeśli już zakończymy odczytywać dane, trzeba zawołać tcp_recved
informując stos, że czekamy na kolejną paczkę. Tu jeszcze jest wszystko
jasne.
Co jednak w sytuacji, gdy powiedzmy do zakończenia wypełniania bufora
pozostało mi 100 bajtów, a w otrzymanej struct pbuf mam ich 500? Na
PIC32 po prostu pobierałem 100, a reszta czekała na swoją kolej. W jaki
sposób uzyskuje się podobny efekt na lwIP?
-
2. Data: 2022-09-24 18:06:33
Temat: Re: lwIP - odbieranie danych przez TCP
Od: "Grzegorz Niemirowski" <g...@g...net>
Atlantis <m...@w...pl> napisał(a):
> W jaki sposób uzyskuje się podobny efekt na lwIP?
Użyć socketów zamiast męczyć się z RAW API?
--
Grzegorz Niemirowski
https://www.grzegorz.net/
-
3. Data: 2022-09-24 19:28:12
Temat: Re: lwIP - odbieranie danych przez TCP
Od: Atlantis <m...@w...pl>
On 24.09.2022 18:06, Grzegorz Niemirowski wrote:
> Użyć socketów zamiast męczyć się z RAW API?
Sockety w lwIP chyba wymagają RTOS-a. Tak to jest zrealizowane na
ESP8266/ESP32 i tam faktycznie nie ma problemu z odbieraniem danych.
Tutaj jednak chciałem to zrobić bezpośrednio na krzemie, więc jestem
skazany na RAW API.
-
4. Data: 2022-09-25 13:34:07
Temat: Re: lwIP - odbieranie danych przez TCP
Od: JDX <j...@o...pl>
On 24.09.2022 19:28, Atlantis wrote:
> On 24.09.2022 18:06, Grzegorz Niemirowski wrote:
>
>> Użyć socketów zamiast męczyć się z RAW API?
>
> Sockety w lwIP chyba wymagają RTOS-a. Tak to jest zrealizowane na
> ESP8266/ESP32 i tam faktycznie nie ma problemu z odbieraniem danych.
> Tutaj jednak chciałem to zrobić bezpośrednio na krzemie, więc jestem
> skazany na RAW API.
>
Ale ,,kernel" np. FreeRTOS-a zajmuje tyle co nic, jeśli mowa o
współczesnych MCU. A idę o zakład, że bardzo ułatwiłby pisanie aplikacji
o nazwie ,,radio internetowe".
BTW:
https://github.com/freertos/freertos-plus-tcp
https://www.freertos.org/FreeRTOS_Support_Forum_Arch
ive/September_2018/freertos_FreeRTOS_TCP_Heap_Consum
ption_89e5ee1aj.html
https://www.freertos.org/FAQMem.html
-
5. Data: 2022-09-25 20:08:30
Temat: Re: lwIP - odbieranie danych przez TCP
Od: Atlantis <m...@w...pl>
On 25.09.2022 13:34, JDX wrote:
> Ale ,,kernel" np. FreeRTOS-a zajmuje tyle co nic, jeśli mowa o
> współczesnych MCU. A idę o zakład, że bardzo ułatwiłby pisanie aplikacji
> o nazwie ,,radio internetowe".
Tyle tylko, że ja już mam działający kod, napisany pod PIC32. Wymaga co
prawda jeszcze paru ulepszeń i poprawek, ale działa. Kod jest napisany z
myślą o działaniu bezpośrednio pod krzemem - opiera się na maszynie
stanów skończonych, zdarzeniach i callbackach. Większość jego
funkcjonalności już udało mi się przenieść pod STM32. To co zostało, to
uruchomienie funkcji samego odbierania streamów z sieci. Tutaj też już
mam jakieś 90% wykonanej pracy - na chwilę obecną prawidłowo łączy się z
serwerem oraz pobiera i parsuje nagłówki HTTP.
Jedyne czego potrzebuje do właśnie rozwiązanie kwestii wyjmowania z
bufora odbiorczego tylko tylu bajtów, ile potrzeba (w zależności od
miejsca w buforze) i zostawienie reszty na później.
Chcąc przenosić to na RTOS musiałbym część pracy zaczynać od nowa. Tak -
samo włączenie FreeRTOS-a to kwestia kilku kliknięć w STM32CubeMX, ale
potem jeszcze trzeba by dostosować inne części projektu do pracy pod tym
systemem.
No i jednak o ile sam system nie zajmuje dużo miejsca we flashu, to już
jednak powoduje zwiększenie zapotrzebowania na RAM.
-
6. Data: 2022-09-25 20:11:45
Temat: Re: lwIP - odbieranie danych przez TCP
Od: "Grzegorz Niemirowski" <g...@g...net>
Atlantis <m...@w...pl> napisał(a):
> Chcąc przenosić to na RTOS musiałbym część pracy zaczynać od nowa. Tak -
> samo włączenie FreeRTOS-a to kwestia kilku kliknięć w STM32CubeMX, ale
> potem jeszcze trzeba by dostosować inne części projektu do pracy pod tym
> systemem.
Nie znam Twojego projektu, ale tego nie powinno być dużo. I tak mniej niż
użerać się z RAW API.
> No i jednak o ile sam system nie zajmuje dużo miejsca we flashu, to już
> jednak powoduje zwiększenie zapotrzebowania na RAM.
FreeRTOS także RAM-u nie potrzebuje dużo.
--
Grzegorz Niemirowski
https://www.grzegorz.net/
-
7. Data: 2022-09-26 05:11:57
Temat: Re: lwIP - odbieranie danych przez TCP
Od: a...@m...uni.wroc.pl
Atlantis <m...@w...pl> wrote:
> Chcia?em ostatnio popchn?? troch? do przodu jeden ze swoich poprzednich
> projekt?w - sprz?towe radio internetowe o kt?rym pisa?em ju? wcze?niej,
> tylko tym razem w wersji ze zaktualizowan? cz??ci? hardware'ow?.
> Poprzednia wersja by?a tworzona na PIC32, teraz powoli chcia?em
> przenie?? go na STM32.
>
> Wi?kszo?? softu w?a?ciwie ju? przenios?em, teraz zosta?o najwa?niejsze -
> przeportowanie samej aplikacji odpowiedzialnej za odtwarzanie streamu z
> Internetu. W przypadku biblioteki MLA na PIC32 by?o to relatywnie
> proste. Socket sieciowy dysponuje buforem FIFO o zdefiniowanej
> pojemno?ci - do niego trafiaj? dane przychodz?ce z serwera. Dane te
> pobieram i ?aduj? do bufora audio. Robi? to jednak dopiero wtedy, gdy
> sterownik uk?adu VS1003 stwierdzi, ?e dane s? potrzebne.
>
> W przypadku PIC32 by?o to relatywnie proste. Mia?em kilka funkcji:
> - TCPIsGetReady() - zwraca?a liczb? bajt?w w buforze
> - TCPGetArray() - funkcja zapisywa?a pod podany adres w pami?ci
> okre?lon? maksymaln? liczb? bajt?w z bufora. Zwraca?a liczb? bajt?w,
> kt?re w rzeczywisto?ci uda?o si? pobra?.
>
> Sprawa by?a prosta - wystarczy?o albo pobra? wszystkie dost?pne dane,
> ale (je?li by?o ich za du?o) tylko tyle, ?eby wype?ni? dost?pne miejsce.
> W tym drugim przypadku nadwy?ka pozostawa?a w buforze gniazda sieciowego
> i by?a sukcesywnie uzupe?niania o kolejne przychodz?ce dane, kt?re
> mog?em pobra? wtedy, gdy zn?w by?y potrzebne.
>
> Widz?, ?e w przypadku lwIP (RAW API) sprawa nie jest ju? tak prosta.
> Zamiast tego musz? zarejestrowa? callback, kt?ry jest wo?any za ka?dym
> razem, gdy przyjd? nowe dane. Callback otrzymuje w jednym z parametr?w
> wska?nik do struct ptr, w kt?rej mam m.in.
> - void* paylod
> - int len
> - int tot_len
> - struct pbuf* next
>
> Istnieje wi?c mo?liwo??, ?e wszystko co b?d? musia? zrobi? to pobranie
> skopiowanie len bajt?w spod adresu na kt?ry wskazuje payload. Istnieje
> jednak szansa, ?e danych jest wi?cej - wtedy tot_len > len i kolejnej
> porcji danych trzeba szuka? w kolejnej strukturze, na kt?r? wskazuje
> wska?nik next.
>
> Je?li ju? zako?czymy odczytywa? dane, trzeba zawo?a? tcp_recved
> informuj?c stos, ?e czekamy na kolejn? paczk?. Tu jeszcze jest wszystko
> jasne.
>
> Co jednak w sytuacji, gdy powiedzmy do zako?czenia wype?niania bufora
> pozosta?o mi 100 bajt?w, a w otrzymanej struct pbuf mam ich 500? Na
> PIC32 po prostu pobiera?em 100, a reszta czeka?a na swoj? kolej. W jaki
> spos?b uzyskuje si? podobny efekt na lwIP?
Nie uzywalem lwIP ale zerknelem do dokumentacji.
Z dokumantacji lwIP wychodzi ze to ma byc "zero copy". Czyli trzymasz
buforki tak dlugo jak sa potrzebne, a potem zwalniasz. Jak cos
zostalo to sobie zapamietujesz polozenie bufora i uzywasz przy kolejnym
callbacku. tcp_recved _nie_ zwalnia buforow, wyglada ze musisz to
robic oddzielnie przez pbuf_free.
--
Waldek Hebisch
-
8. Data: 2022-09-26 09:09:46
Temat: Re: lwIP - odbieranie danych przez TCP
Od: Atlantis <m...@w...pl>
On 26.09.2022 05:11, a...@m...uni.wroc.pl wrote:
> Nie uzywalem lwIP ale zerknelem do dokumentacji.
> Z dokumantacji lwIP wychodzi ze to ma byc "zero copy". Czyli trzymasz
> buforki tak dlugo jak sa potrzebne, a potem zwalniasz. Jak cos
> zostalo to sobie zapamietujesz polozenie bufora i uzywasz przy kolejnym
> callbacku. tcp_recved _nie_ zwalnia buforow, wyglada ze musisz to
> robic oddzielnie przez pbuf_free.
Ok, czyli chyba faktycznie najprościej będzie posłużyć się dodatkowym
buforem pomocniczym, w którym trzymałbym nadwyżkę. Na dobrą sprawę można
by nawet alokować te dane dynamicznie, na stercie. Wtedy po prostu przed
zapisaniem kolejnej paczki sprawdzałoby się czy wskaźnik do bufora
pomocniczego ma wartość inną niż NULL, zapisywało te dane do głównego
bufora, zwalniało pomocniczy i przypisywało NULL do wskaźnika. Dopiero
wtedy go głównego bufora szłaby paczka nowych danych, a jeśli coś by
zostało, to nadwyżka trafiałaby do zaalokowanego na nowo bufora
dynamicznego.
To chyba jednak bardziej eleganckie rozwiązanie niż opóźnianie
zwalniania całej struktury pbuf do kolejnego callbacka.
Po prostu miałem nadzieję, że można to zrobić bez takich kombinacji,
jedynie pobierając potrzebny w danej chwili kawałek bufora, jak w
przypadku MLA na PIC32.
-
9. Data: 2022-09-26 17:33:13
Temat: Re: lwIP - odbieranie danych przez TCP
Od: Atlantis <m...@w...pl>
W sumie mam jeszcze inny pomysł. W układzie mam układ pamięci RAM na
SPI. W późniejszej wersji softu planowałem go wykorzystać w roli nieco
większego bufora audio, jednak chyba wykorzystam go jako bufor
cykliczny, pośredniczący w komunikacji pomiędzy siecią a dekoderem MP3.
W callbackach lwIP będę po prostu ładował kolejne przychodzące dane do
kolejnych adresów w tym układzie, a maszyna stanów obsługująca
odtwarzanie będzie je sobie pobierała, uzupełniając swój własny,
mniejszy bufor w pamięci mikrokontrolera. To powinno mi pozwolić na
rozwiązanie kwestii przekazywania danych w sposób asynchroniczny.
-
10. Data: 2022-09-27 15:35:51
Temat: Re: lwIP - odbieranie danych przez TCP
Od: "J.F" <j...@p...onet.pl>
On Sat, 24 Sep 2022 17:58:49 +0200, Atlantis wrote:
> Chciałem ostatnio popchnąć trochę do przodu jeden ze swoich poprzednich
> projektów - sprzętowe radio internetowe o którym pisałem już wcześniej,
> tylko tym razem w wersji ze zaktualizowaną częścią hardware'ową.
> Poprzednia wersja była tworzona na PIC32, teraz powoli chciałem
> przenieść go na STM32.
A tak swoja drogą - te radia działają na TCP ?
Bo chyba powinny na UDP ...
Kolejna sprawa - jak te radia działają?
Dawniej podawali jakies parametry do bezposredniej transmisji,
dzis wszystko pochowane. Wyswietl nasza strone www.
A radia (te niby "sprzetowe") jakos działają ... maja jakies serwery
z listami parametrów ?
> Widzę, że w przypadku lwIP (RAW API) sprawa nie jest już tak prosta.
> Zamiast tego muszę zarejestrować callback, który jest wołany za każdym
> razem, gdy przyjdą nowe dane. Callback otrzymuje w jednym z parametrów
> wskaźnik do struct ptr, w której mam m.in.
> - void* paylod
> - int len
> - int tot_len
> - struct pbuf* next
>
> Istnieje więc możliwość, że wszystko co będę musiał zrobić to pobranie
> skopiowanie len bajtów spod adresu na który wskazuje payload. Istnieje
> jednak szansa, że danych jest więcej - wtedy tot_len > len i kolejnej
> porcji danych trzeba szukać w kolejnej strukturze, na którą wskazuje
> wskaźnik next.
>
> Jeśli już zakończymy odczytywać dane, trzeba zawołać tcp_recved
> informując stos, że czekamy na kolejną paczkę. Tu jeszcze jest wszystko
> jasne.
>
> Co jednak w sytuacji, gdy powiedzmy do zakończenia wypełniania bufora
> pozostało mi 100 bajtów, a w otrzymanej struct pbuf mam ich 500? Na
> PIC32 po prostu pobierałem 100, a reszta czekała na swoją kolej. W jaki
> sposób uzyskuje się podobny efekt na lwIP?
Na moj gust, gdzies musisz sobie założyc bufor odpowiedniej dlugosci,
wpychac tam dane które przyszly, i potwierdzac otrzymanie, lub
poczekac jak sie bufor konczy ... aby zatrzymac transmisje.
J.