Jak nejlépe formátovat pole znaku

Wiring, C++, C, Java, ...
Pravidla fóra
Toto subfórum slouží k řešení obecných otázek kolem programování (konstrukce, knihovny, alokace paměti, ...)
ARDDedek
Příspěvky: 12
Registrován: 21 bře 2023, 08:41
Reputation: 0

Jak nejlépe formátovat pole znaku

Příspěvek od ARDDedek » 21 bře 2023, 10:24

Rovnou se přiznám že jsem sice mnohaletý programátor a elektronik (dnes již penzionovaný), ale současně platí že s arduinem teprve začínám a pointrovou matematiku od C/C++ lovím z prehistorické cache mého brainu.

Níže uvedený kód mi má pouze sestavit pole charu pro následné odeslaní přes Ethernet Shield.
Neřešte prosím HTML kód.

Chyba se momentalně projevuje tak že do konzole se patricny text vypisuje jen omezenou dou cca 20s a potom celý program zatuhne a musím stisknout RESET na ARDUINO chipu.

Do výsledného projektu a současně k testům používám Arduino Nano https://dratek.cz/arduino/936-ethernet- ... -nano.html

Kód: Vybrat vše

void loop() {
  //CteniKlavesnice();
  //CteniKlavesniceI2C();
  // CteniDHT();
  // CteniHladiny();
  // BlikaniBUILDIN_LED();
  // OvladaniRelatek();
  //CteniCasuDS1302();
  // ZapisOLED_SSD1306();
  //ZapisLiquidDisplay();
  CteniEthernetShield();
  // char* b = IntToString(random());
  // VypisDebugText(b);
  // free(b);
  delay(2000);
}

void CteniEthernetShield() {
  String nactiOdpoved;
  EthernetClient klient = server.available();
  OdeslemeStandartniOdpoved(klient, 15);
  }
  
void OdeslemeStandartniOdpoved(EthernetClient klient, int refresh) {
  char buff[250];
  buff[0] = 0;
  strcat(buff, "HTTP/1.1 200 OK\n");                        //klient.println("HTTP/1.1 200 OK");
  strcat(buff, "Content-Type: text/html;charset=utf-8\n");  // klient.println("Content-Type: text/html;charset=utf-8");
  strcat(buff, "Connection: close\n");                      // klient.println("Connection: close");
  if (refresh > 0) {
    strcat(buff, "Refresh: ");
    char d[12];  // klient.println("Refresh: 5");
    itoa(refresh, d, 10);
    strcat(buff, d);
    strcat(buff, "<!DOCTYPE HTML>\n<html>\n");  // klient.println("<!DOCTYPE HTML>");
    strcat(buff, "cas od spusteni: ");
    itoa(millis() / 1000, d, 10);  // klient.print(millis() / 1000);
    strcat(buff, d);
    strcat(buff, "\n</html>");
  }
  VypisDebugText(buff);
  VypisDebugInfo("Delka textu %d", strlen(buff));
}

V uvedeném kódu je vidět sekvence volaní a já bohužel zatím neumím debugovat v arduino studiu v: 2.0.4

Teď celý program běžel cca 89s.
Spuštěno v "09:42:48.219 -> Server je na IP adrese: 192.168.0.220"
Ukončeno v "09:44:16.320"

Díky za každou radu

ondraN
Příspěvky: 932
Registrován: 08 srp 2019, 20:01
Reputation: 0

Re: Jak nejlépe formátovat pole znaku

Příspěvek od ondraN » 21 bře 2023, 13:06

Myslím, že by ten problém mohlo způsobit přetečení zásobníku. Arduino má malou paměť a tím i omezený zásobník. Ty tam alokuješ buff o velikosti 250byte, což zásobník téměř zaplní. Když se pak zavolá ještě něco dalšího, je vymalováno. Zkus ten buffer definovat jako static char buff[250];
Pak se ti vytvoří v dolní paměti a bude tam trvale. Pokud budeš bojovat s nedostatkem paměti, musíš si nějak bufer sdílet, nebo texty tisknout jako literály z Flash paměti (makro F v printu).

Uživatelský avatar
kiRRow
Příspěvky: 1152
Registrován: 07 kvě 2019, 07:03
Reputation: 0
Bydliště: Opava

Re: Jak nejlépe formátovat pole znaku

Příspěvek od kiRRow » 21 bře 2023, 15:52

Arduino UNO má 2048 byte SRAM, char[250] zabere 2000 byte, spodní část SRAM se používá pro ukládání adresy, když procesor někam odskakuje, horní část je použita pro globální proměnné a mezitím je prostor pro dočasné proměnné. Pokud dočasné proměnné se vlivem své velikosti, nebo vlivem fragmentace paměti dostanou až do části, kterou procesor používá pro uložení adresy dojde k přepsání této adresy a procesor se pak vrátí na špatné místo a program vytuhne, nebo začne dělat psí kusy. Nabourá se ti heap do stacku.

Dá se toho i krásně dosáhnout i s malými řetězci ... alokuješ char[16], alokuješ jeden bit, uvolníš z paměti char[16], alokuješ jeden bit a pořád dokola - paměť bude z velké části volná, ale nikde už v ní nezbyde spojité místo pro char[16], program zhavaruje.

Co takhle použít externí paměť ? Nebo SD kartu - ta se ti bude i lépe "programovat".

peterple
Příspěvky: 156
Registrován: 22 zář 2021, 20:20
Reputation: 0

Re: Jak nejlépe formátovat pole znaku

Příspěvek od peterple » 21 bře 2023, 19:45

Nerozumiem prečo , char[250] zaberie 2000 byte. Podľa mňa zaberie 250 bytov.
Tiež nerozumiem prečo ho strašíš fragmentáciou. Lokálne premenné sa alokujú na zásobníku a nie na hromade. Takže po skončení funkcie všetko zmizne ako para nad hrncom. Žiadna fragmentácia sa nekoná.

Ja tam zas až taký veľký dôvod k zaplnenosti 2048 bytov nevidím. Zasobník a statické premenné idú proti sebe, takže prešupnutie premennej z lokálnej na globálnu myslím situáciu nevyrieši. Neviem aký nenažraný je ten EthernetClient objekt a či sídli v zásobníku alebo si alokuje buffre aj na hromade. Poteciálne by tento mohol spôsobovať tú fragmentáciu a nakoniec nedostatok pamäte.

Myslím že tu sa deje niečo hodne nekalého. Bez debugovania to asi nepôjde.
Debugovanie Arduina na procesoroch AVR je trochu iný level. Na to potrebuješ poriadny hw debugger a moje skúsenosti sú že to chvílu funguje - potom nefunguje. Potom viac času zabiješ opakovanými štartami ako debugovaním. Ja zásadne debugujem takéto systémy iba cez logovanie na seriovú linku.
Doporučujem teda vypisovať na sériovú linku rozumné množstvo informáciíí. A testovať jednu vec za druhou ktorá by to mohla spôsobiť

Pri takýchto malých systémoch do toho musí človek poriadne vidieť a nemôže to programovať ako PC. Takže rada od ondry o presunutí konštantných stringov do pamäte FLASH je veľmi dobrá. Ale opäť treba do toho vidieť. Rozumieť že ten AVR má harwardskú architektúru a ako to oklamali v C ktoré normálne takú vec nepodporuje.

Uživatelský avatar
kiRRow
Příspěvky: 1152
Registrován: 07 kvě 2019, 07:03
Reputation: 0
Bydliště: Opava

Re: Jak nejlépe formátovat pole znaku

Příspěvek od kiRRow » 21 bře 2023, 20:46

máš pravdu, chyba na mé straně ... char je byte a netřeba násobit 250, ale k fragmentaci paměti stále docházet může - právě že nevíme jak pracuje s paměti ta ethernet knihovna ...

Vše statické zabere začátek paměti (někde možná i konec, ale je to pevně ukousnutý kus paměti), lokální proměnné se alokují na hromadě, zásobník je na druhém konci paměti, hromada a zásobník se pohybují proti sobě.

ARDDedek
Příspěvky: 12
Registrován: 21 bře 2023, 08:41
Reputation: 0

Re: Jak nejlépe formátovat pole znaku

Příspěvek od ARDDedek » 21 bře 2023, 21:27

Vsem dekuji za prispevky.
Přesunutí toho bufferu do static mode pomohlo ale stejne plati myslenka o defragmentaci pameti.
I ja ve svem prof. zivote ucil ze lokalni promena metody po zkonceni proste zmizi jak para nad hrncem. Samozrejmne ze pokud bych alokoval pomoci nejake funkce ...allock tak ji budu muset uvolnit.
Spis bych se chtel zeptat na to skladani dlouheho textu je muj kod v poradku (myslim tim technika naplneni toho bufferu) nebo by jste to napsaly jinak.

V.

peterple
Příspěvky: 156
Registrován: 22 zář 2021, 20:20
Reputation: 0

Re: Jak nejlépe formátovat pole znaku

Příspěvek od peterple » 21 bře 2023, 21:28

Opäť musím nesúhlasiť. Lokálne premenné sa alokujú v zásobníku. Na hromade sa vytvárajú premenné buď volaním funkcie malloc alebo pomocou operátora new v objektovom programovaní

ARDDedek
Příspěvky: 12
Registrován: 21 bře 2023, 08:41
Reputation: 0

Re: Jak nejlépe formátovat pole znaku

Příspěvek od ARDDedek » 21 bře 2023, 21:38

Skym nesouhlasis

peterple
Příspěvky: 156
Registrován: 22 zář 2021, 20:20
Reputation: 0

Re: Jak nejlépe formátovat pole znaku

Příspěvek od peterple » 21 bře 2023, 21:40

ARDDedek:

Pozor na to že presunutím z lokalnej premenej na globálnu si možno problem neodhalil len si ho presunul tak že nemá momentálne fatálne následky. Teraz keď to nie je v zásobníku tak to stále môže prepisovať pamäť za tým ale už to nemá deštrukčný účinok nakoľko nepošaháš návratovú adresu ale iba nejaké data v pamäti.

To generovanie by mohlo aj byť, len by som to nerobil tromi strcat za sebou ale jedným a dal by som ten text do pamäte flash pomocou makra F

Toto by som doporučoval preštudovať
https://docs.arduino.cc/learn/programming/memory-guide
Veci týkajúce sa ARMov môžeš ignorovať.

nesúhlasím s
kiRRow píše:
21 bře 2023, 20:46
lokální proměnné se alokují na hromadě,

Uživatelský avatar
kiRRow
Příspěvky: 1152
Registrován: 07 kvě 2019, 07:03
Reputation: 0
Bydliště: Opava

Re: Jak nejlépe formátovat pole znaku

Příspěvek od kiRRow » 21 bře 2023, 21:42

peterple píše:
21 bře 2023, 21:28
Opäť musím nesúhlasiť. Lokálne premenné sa alokujú v zásobníku. Na hromade sa vytvárajú premenné buď volaním funkcie malloc alebo pomocou operátora new v objektovom programovaní
Ano máš pravdu.

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 8 hostů