RTV forum PL | NewsGroups PL

Przenoszenie internetowego radia z PIC32 na STM32 za pomocą lwIP i TCP

lwIP - odbieranie danych przez TCP

NOWY TEMAT

elektroda NewsGroups Forum Index - Elektronika Polska - Przenoszenie internetowego radia z PIC32 na STM32 za pomocą lwIP i TCP

Goto page 1, 2, 3  Next

Atlantis
Guest

Sat Sep 24, 2022 3:58 pm   



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?

Grzegorz Niemirowski
Guest

Sat Sep 24, 2022 4:06 pm   



Atlantis <marekw1986NOSPAM@wp.pl> napisał(a):
Quote:
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/

Atlantis
Guest

Sat Sep 24, 2022 5:28 pm   



On 24.09.2022 18:06, Grzegorz Niemirowski wrote:

Quote:
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.

JDX
Guest

Sun Sep 25, 2022 11:34 am   





Atlantis
Guest

Sun Sep 25, 2022 6:08 pm   





Grzegorz Niemirowski
Guest

Sun Sep 25, 2022 6:11 pm   



Atlantis <marekw1986NOSPAM@wp.pl> napisał(a):
Quote:
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.

Quote:
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/

Guest

Mon Sep 26, 2022 5:11 am   



Atlantis <marekw1986NOSPAM@wp.pl> wrote:
Quote:
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

Atlantis
Guest

Mon Sep 26, 2022 7:09 am   



On 26.09.2022 05:11, antispam@math.uni.wroc.pl wrote:

Quote:
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.

Atlantis
Guest

Mon Sep 26, 2022 3:33 pm   



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.

J.F
Guest

Tue Sep 27, 2022 1:35 pm   



On Sat, 24 Sep 2022 17:58:49 +0200, Atlantis wrote:
Quote:
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 ?

Quote:
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.

Mateusz Viste
Guest

Tue Sep 27, 2022 3:12 pm   



2022-09-27 o 15:35 +0200, J.F napisał:
Quote:
A tak swoja drogą - te radia działają na TCP ?
Bo chyba powinny na UDP ...

Z reguły jednak TCP. Co gorsze - nierzadko z dodatkową warstwą TLS.
Przykłady streamów:

https://31.192.216.10/RMF2
https://radiovassiviere.ice.infomaniak.ch/radiovassiviere-128.aac
http://stream3.nadaje.com:9000/;stream/1

Quote:
Dawniej podawali jakies parametry do bezposredniej transmisji,
dzis wszystko pochowane. Wyswietl nasza strone www.

Da się znaleźć, np. tu:
https://online-radio.eu/

W domu mały NAS Linuksowy z VLC robi za radio, podaję mu URLe
skopiowane właśnie z powyższej strony.

Mateusz

Cezar
Guest

Tue Sep 27, 2022 3:22 pm   



On 27/09/2022 14:35, J.F wrote:
Quote:
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 ...

Wszysto idzie po TCP. UDP jest cięzkie do implementacji po stronie
klienta bo trzeba ogarnąć:
- jitter
- packet loss
- out of order packets

Oczywiście da się to ogarnąc bo tak działa cały VoIP...
Myślę że łatwość implementacji klienta tutaj wygrała - większość
streamów to TCP (HTTP)




Quote:
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 ?


Atlantis
Guest

Wed Sep 28, 2022 7:30 am   



On 27.09.2022 15:35, J.F wrote:

Quote:
A tak swoja drogą - te radia działają na TCP ?

Działają na TCP, a konkretnie na zwyczajnym protokole HTTP. Otwierasz
połączenie z serwerem i wysyłasz GET-a, prosząc o udostępnienie
konkretnego streamu. W odpowiedzi dostajesz odpowiedź i nagłówki. Jeśli
jest to 200 OK, możesz zacząć odbierać i dekodować przychodzące dane
audio. Oczywiście trzeba też obsłużyć inne sytuacje, jak np.
przekierowanie pod inny adres.

Quote:
Bo chyba powinny na UDP ...

Po co? Strumień audio nie potrzebuje niskiej latencji - wszystko i tak
jest buforowane po stronie serwera. Można się o tym dość łatwo przekonać
włączając jednocześnie dowolne radio FM i jego sieciowy odpowiednik,
albo jeszcze lepiej - Jedynkę na falach długich i tę samą stację
nadawaną on-line.


Quote:
Kolejna sprawa - jak te radia działają?
Dawniej podawali jakies parametry do bezposredniej transmisji,
dzis wszystko pochowane. Wyswietl nasza strone www.

Niektóre stacje nadal podają bezpośrednie URL-e do swoich streamów. Jest
też trochę różnych zestawień w Internecie. W przypadku stacji
narzucających własną aplikację na stronie i tak bardzo często pod spodem
mamy zwyczajne połączenie HTTP - wtedy wystarczy wyłuskać adres
analizując ruch, np. za pomocą narzędzi deweloperskich Chrome'a.


Quote:
A radia (te niby "sprzetowe") jakos działają ... maja jakies serwery
z listami parametrów ?

Tak. I to jest właśnie głównym powodem dla którego zabrałem się za ten
projekt. Wkurzał mnie fakt, że większość dostępnych komercyjnie
rozwiązań będzie działała tak długo, jak długo producent raczy
utrzymywać infrastrukturę. Tutaj sam wpisuję URL-e stacji, które chcę
słuchać.


Quote:
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.

No właśnie tutaj jak na razie rozbijam się o szczegóły. W przypadku
stosu MLA z PIC32 po prostu pobierałem sobie z bufora odbiorczego tyle
danych, ile w danym momencie potrzebowałem. Stos robił pod spodem całą
resztę - jeśli w buforze było miejsce, prosił serwer o więcej danych.
Efekt był taki, że dekoder MP3 z automatu narzucał prędkość transmisji i
nawet przy stosunkowo niewielkich buforach wszystko działało płynnie.

Tutaj sprawa jest trochę bardziej skomplikowana. Dane nie są buforowane
w taki sposób i nie mogę po prostu pobrać dowolnej ilości w dowolnym
momencie. Jeśli zostanie wywołany callback odbiorczy, mam obowiązek
odebrać całą paczkę, zwolnić pamięć i wywołać tcp_recved. Jednak z tego
co rozumiem ta ostatnia funkcja jedynie zwiększa rozmiar okna
odbiorczego, więc nawet pomimo braku jej wywołania nie mam gwarancji, że
jeszcze przez chwilę nie przyjdą kolejne callbacki - być może uda mi się
uzyskać taki efekt odpowiednio manipulując ustawieniami stosu.

Przerobiłem wczoraj nieco swoją aplikację, implementując bufor cykliczny
do którego trafiają dane ze strumienia. Serwer jednak wysyła je nieco
szybciej niż wynikałoby to z bitrate'u strumienia audio - ma to sens, bo
nadmiarowe dane w normalnych warunkach mogą zostać użyte do uzupełniania
bufora. Tak więc jeśli po prostu odbieram dane, wrzucam je do bufora i
potwierdzam otrzymanie, to dość szybko dochodzi do przepełnienia bufora
- dźwięk jest, ale postrzępiony. Próbowałem wywoływać tcp_recved() w
innym miejscu dopiero wtedy, gdy w buforze była dostatecznie dużo
wolnego miejsca, jednak jak na razie nie udało mi się uzyskać poprawnego
działania. Będę jeszcze eksperymentował.

Eksperymenty z zewnętrzną pamięcią SPI RAM 128 kB jak na razie też nie
przyniosły idealnych rezultatów. Nawet przy maksymalnej
dostępnej prędkości (18 MHz) wydaje się ona zwyczajnie zbyt wolna.
Trochę mnie to zaskoczyło, bo karta SD przy dwa razy wolniejszej
transmisji spokojnie wyrabiała z dostarczaniem danych z pliku MP3. Z
drugiej strony jednak tutaj mam operacje odczytu i zapisu, występujące
naprzemiennie w krótkich odstępach czasu.

Zaczynam zastanawiać się czy faktycznie dobrym pomysłem nie będzie
zastosowanie FreeRTOS-a i socketów. Nie wiem tylko czy problemem nie
będzie niewielka ilość RAM-u mikrokontrolerze (64kB).

Atlantis
Guest

Wed Sep 28, 2022 7:35 am   



On 27.09.2022 17:12, Mateusz Viste wrote:

Quote:
W domu mały NAS Linuksowy z VLC robi za radio, podaję mu URLe
skopiowane właśnie z powyższej strony.

Moje pierwsze podejście do tematu autonomicznego radia internetowego
polegało właśnie na wykorzystaniu Raspberry Pi (Zero) z zewnętrznym
DAC-iem i standardowym oprogramowaniem do odtwarzania audio (MPD) pod
spodem. Otwierało to sporo dodatkowych możliwości, jednak trochę
absurdalny wydawał mi się fakt, że urządzenie musi najpierw załadować i
uruchomić cały system operacyjny, żeby zacząć odbierać stację. W celach
edukacyjnych postanowiłem więc złożyć wersję na mikrokontrolerze. Wink

Mateusz Viste
Guest

Wed Sep 28, 2022 8:52 am   



2022-09-28 o 09:35 +0200, Atlantis napisał:
Quote:
On 27.09.2022 17:12, Mateusz Viste wrote:

W domu mały NAS Linuksowy z VLC robi za radio, podaję mu URLe
skopiowane właśnie z powyższej strony.

Moje pierwsze podejście do tematu autonomicznego radia internetowego
polegało właśnie na wykorzystaniu Raspberry Pi (Zero) z zewnętrznym
DAC-iem i standardowym oprogramowaniem do odtwarzania audio (MPD) pod
spodem. Otwierało to sporo dodatkowych możliwości, jednak trochę
absurdalny wydawał mi się fakt, że urządzenie musi najpierw załadować
i uruchomić cały system operacyjny, żeby zacząć odbierać stację. W
celach edukacyjnych postanowiłem więc złożyć wersję na
mikrokontrolerze. Wink

Chwalebnie... i ambitnie - bo trzeba samemu obsłużyć TCP, HTTP,
kilka popularnych kodeków, TLS... sporo warstw do przebicia.
Niemniej doceniam i rozumiem myśl. Też mnie denerwuje, że po włączeniu
"radia" muszę czekać niemal minutę na dźwięk.

Mateusz

Goto page 1, 2, 3  Next

elektroda NewsGroups Forum Index - Elektronika Polska - Przenoszenie internetowego radia z PIC32 na STM32 za pomocą lwIP i TCP

NOWY TEMAT

Regulamin - Zasady uzytkowania Polityka prywatnosci Kontakt RTV map News map