Adatok kiválogatása soros portról

Sziasztok!

Arduino programozással foglalkozom és egy dologban nem vagyok teljesen biztos.
Soros portra tudok vele adatokat küldeni, és erre válaszol is a céleszköz, viszont az a nagy problémám, hogy hogyan tudnék én abból kiválogatni bizonyos adatokat aztán eltárolni változókban.

Konkrétan arról van szó, hogy van egy ADSL modemem, amivel nagyon jól lehet mérni mindenféle paramétert és egy kijelzőt szeretnék rá csinálni (a menü meg a funkciók már működnek, már csak fel kellene tölteni adatokkal a változókat) + akksi + 1-2 gomb és lesz egy mobil mérő eszközöm. Sajna VDSL-t nem tud, de kezdésnek nem rossz. Ha kész lesz majd közzéteszem a forráskódját meg mindenfélét róla.

Szóval ilyen jellegű adatok várhatók a soros porton:


> adsl info --stats
adsl: ADSL driver and PHY status
Status: ShowtimeRetrain Reason: 8000
Channel: FAST, Upstream rate = 639 Kbps, Downstream rate = 12470 Kbps
Link Power State: L0
Mode: ADSL2+
Channel: Interleave
Trellis: U:ON /D:ON
Line Status: No Defect
Training Status: Showtime
Down Up
SNR (dB): 10.3 34.3
Attn(dB): 5.5 3.9
Pwr(dBm): 17.9 11.5
Max(Kbps): 21292 1549
Rate (Kbps): 12470 639
G.dmt framing
K: 39(0) 10
R: 16 16
S: 1 16
D: 32 4
ADSL2 framing
MSGc: 59 11
B: 38 9
M: 1 16
T: 10 8
R: 16 16
S: 0.0998 7.9101
L: 4408 178
D: 288 4
Counters
SF: 87001 88188
SFErr: 0 0
RS: 56551164 712565
RSCorr: 1 0
RSUnCorr: 0 0

HEC: 0 7267
OCD: 0 0
LCD: 0 0
Total Cells: 41499362 135258638
Data Cells: 802 99654931
Drop Cells: 0
Bit Errors: 0 508957

ES: 0 263
SES: 0 84
UAS: 1812 13923
AS: 1412

INP: 4.18 1.43
PER: 16.22 16.80
delay: 7.18 7.91
OR: 32.05 8.09

Bitswap: 2 1

Total time = 1 hours 26 min 39 sec
SF = 87001
CRC = 0
LOS = 0
LOF = 0
ES = 0
Latest 1 day time = 1 hours 26 min 39 sec
SF = 87001
CRC = 0
LOS = 0
LOF = 0
ES = 0
Latest 15 minutes time = 11 min 39 sec
SF = 43161
CRC = 0
LOS = 0
LOF = 0
ES = 0
Previous 15 minutes time = 15 min 0 sec
SF = 43840
CRC = 0
LOS = 0
LOF = 0
ES = 0
Previous 1 day time = 0 sec
SF = 0
CRC = 0
LOS = 0
LOF = 0
ES = 0
15 minutes interval [-30 min to -15 min] time = 15 min 0 sec
SF = 0
CRC = 0
LOS = 0
LOF = 0
ES = 0
15 minutes interval [-45 min to -30 min] time = 15 min 0 sec
SF = 0
CRC = 0
LOS = 0
LOF = 0
ES = 0
15 minutes interval [-60 min to -45 min] time = 15 min 0 sec
SF = 0
CRC = 0
LOS = 0
LOF = 0
ES = 0
Showtime Drop Reason: 8000
Last Retrain Reason: 8000
>

Ebből nekem például kellene az UP/DOWN stream értékek, status értéke, mondjuk a trellis is, training status... igazából szinte minden egyes érték.
Azt nem tudom, hogy amikor a parancs után elárasztja a válasz a sorosportot, akkor egyáltalán tárolja-e az eszköz az adatokat (de tudtommal nem, szóval valós időben kell feldolgozni). Valahogy meg kellene különböztetni a szavakat, szóközöket, értékeket egymástól, hogy be tudjam olvasni a megfelelő értékeket megfelelő változókba.

Valaki tudna ebben segíteni?

Köszönöm!

(közben én is nyomozok majd holnap munka után)

Hozzászólások

Az Atmega168 csip (ami az Arduinoban van) egy 8 bites mikrovezérlő, ebben a serial input úgy van megvalósítva, hogy egyetlen bájtnyi hardveres puffer van az adatnak, ezt ki kell olvasni, mielőtt a következő bájt jönne. Ez azért nem annyira rövid idő, hogy mission impossible legyen.

Az Arduino beépített Serial libje csak szinkron módon működik, ha jól emlékszem, ez azt jelenti, hogy nincsen semmi pufferelés, ha éppen nem olvastad ki az adatot, akkor úgy jártál. De még ezzel is működhet a program, ha a loop metódusban minden körben megpróbálsz adatot olvasni, és nincs sok más amit csinálni kell (pl képernyő frissítés). Számolni vagy mérni (jelző bitek ki/bekapcsolása a program szakaszain, és ezt szkóppal meg kell nézni milyen hosszú pulzust ad ki) kell, hogy mi mennyi idő.

Ha csinálsz egyedi megvalósítást (mondjuk C-ben Arduino nélkül, vagy akár Arduino-n belül is lehet), akkor pollozás helyett kezelheted a soros port interruptot, akkor a main loop-ot nem kell terhelni vele. A RAM-ba tehetsz egy valamivel hosszabb input buffert, akkor biztosan nem veszíted el a bejövő bájtokat. Ebből a pufferből (pl ringbuffer megvalósítás lehet) szintén a main loop-ból lehet olvasni, de ekkor már sokkal kevésbé éles időzítéssel. A másik megoldás, hogy az inputot nem buffereled, hanem azonnal feldogozod - még az IT rutinon belül. Ízlés kérdése :-).

Ha Arduino IDE nélkül, közvetelenebb módon C-ben akarod programozni az Arduino-t, azt is lehet, ezen topikban volt róla sok szó, hogy pontosan hogyan: http://hup.hu/node/139796

Arduino IDE- ben csinálnám.

Hát őszintén szólva voltak olyan részei -annak amit írtál- ami nem teljesen tiszta.
Na de majd utánanézek. Szerintem előtte csinálok egy kis helyet az SRAM-ban mert már eléggé tele van, átteszem a statikus dolgokat a FLASH-re.
Egyébként ATMega328 van már az újakban. Nekem is az van. 32K FLASH, 2K RAM. :D

Arduino-t nem ismerem, de az AVR-eket igen. Ha rendes C fordítót használsz, akkor lesz string.h, stdlib.h. strstr, atoi függvényeket javaslom. Tárold el az adatot egy statikus bufferbe soronként, és elemezd ki.
A lebegőpontos értékek sajnos szívás. A fordító megcsinálja, de nagy és lassú kódot fog generálni. Oda más megoldást javasolnék, esetleg fixpontosra konvertálást.

Ha már ilyen okos modem, nem tud véletlen grep-et? Úgy azért nagyságrendekkel egyszerűbb lenne. Ha meg még cut-ot és/vagy awk-t esetleg sed-et is, akkor főleg.

busybox úgy tűnik bejött, sh-t ismeri

viszont grep-et nem.

Ezeket a parancsokat ismeri:

. : break cd continue eval exec exit export help login newgrp
read readonly set shift times trap umask wait [ busybox cat chmod
cp date df dmesg echo expr false ftpget fuser ifconfig init insmod
kill killall klogd linuxrc ln logger logread ls mkdir mknod mount
msh nslookup pidof ping ps pwd reboot rm rmmod route sendarp
sh sync sysinfo syslogd test tftp tftpd top true tty umount vconfig

Nézd meg a \hardware\arduino\avr\cores\arduino\HArdwareSerial.h-ban az SERIAL_RX_BUFFER_SIZE értékét (függhet az SRAM-tól).
Valszin 16 lesz, tehát 16 bejövő soros byte-ot bufferel a rendszer. Megoldástól és baud rate-től függően ez vagy elég, vagy meg kell növelni.

Én azt csinálnám, hogy minden ciklusban az összes beérkezett byte-ot egy saját bufferbe másolnám át ("while (Serial.Available()....." ). Sorvége karakternél kielemezném a saját buffer tartalmát (mondjuk strncmp-vel), majd elemzés után kitörölném. Ha pl. "Rate (Kbps): "-tel kezdődik, akkor kiolvasom a Rate értékét. De az "sscanf"-fel kell csínján bánni: az sscanf futása elég lassú, több millisec-be is betellhet, mialatt a háttérben újabb karakterek érkeznek és töltik fel a Serial bufferét (SERIAL_RX_BUFFER_SIZE).
A saját buffer mérete legalább a várható leghosszabb sor hossza legyen, de persze figyelni kell, hogy ennél hosszabb sor nem okozzon galibát.

A szomszédos topicban asm vs. C volt a téma. Én elsősorban asm mellett igyekeztem érvelni, miközben ki-ki arról győzködött, hogy a C-ben írt kód közel ugyanannyira hatékony. Vagy az nem igaz, vagy, amit itt írtok.

Mondjuk legyen a konroller sebessége 2 Mips. 19200 8n1 esetén 2 byte között eltelik kb. 1041 utasítás. Ennyi utasításból mit nem lehet megcsinálni? LF karakterek mentén sort törni, néhány 10 byte-os sorra mintát illeszteni, valami állapotautomatát írni?

Nyilván, ha általános célú könyvtári függvényeket használ valaki, akkor lehet lassú, de feladat orientáltan assembly-ben megírva nagyjából unatkozni fog a CPU, annyi szabadideje marad még valós idejű feldolgozás esetén is.

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Úgy látszik, ez valami életkori sajátosság. Mikrokontrolleren nem gondolkodom valamilyen objektum-orientált nyelvben, amelyet esetleg valami interpreter futtat. ;)

Amúgy újabb érv az assembly mellett: hiába hatékony a C, ha nem nagyon tudom megbecsülni, mennyi idő alatt fut a kód. Assembly-ben ez azért elég jól látszik. Tudom, a C-ből fordított kód is megnézhető, csak azzal számolni kellemetlen, hiszen amit a compiler írt, az valami idegen furcsaság, amit én, arról tudom, hogy micsoda.

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

No, azért ne túlozzunk! Inkább azt lehet mondani, hogy a mikrokontrollerekhez keszült C fordítók és libek minősítése: fostalicska. Van olyan C fordító, amelyik ilyet ír ki a függvény végére:
Instruction count 78
Straight-line exec time 61
Ugyan csak a PIC-eket használom, de vagyok olyan elfogult, hogy más mikrokontroller fejlesztőeszközeiről is rosszat tételezzek fel. ;)
Ami döbbenetes:
1) Legkisebb eltérésre - ami nem lenne szabad - teljesen más, igen gyakran ostobaságot fordít.
2) Rengeteg felesleges, és értelmetlen kódot fordít. Egyszer egy rövid szakaszon megvizsgáltam az egyes opciók, és átrendezés eredményét. Akkor csak egy push+pop jellegű utasításpár maradt feleslegesen.
3) Próbáltam libből "kódot lopni" - abszolút felesleges erőfeszítésnek bizonyult. Liter pálinka után, a gépnek háttal jobb kódot írok.
4) Első kísérletem az eeprom írásra: A dokumentációból kivettem a kódot - lefagy. Libből kiollóztam a kódot - hülyeséget ír. Elolvastam a doksit, megírtam, működik. Az eredeti cél időmegtakarítás lett volna. :(

Persze nem kizárt, hogy 30 évet meghaladó asm, és 20 évet meghaladó C gyakorlattal (nem hobbi) én nem értek semmihez.

Az asm nem hordozható, ezért a soros portról olvasást kénytelen voltam portolni PIC18-ra a 18 éve írt, 80186-ra készült asm forrásból. Természetesen interrupt felhasznalásával. Így a "Straight-line exec time" kb 50 órajel, memória felhasználás 5+buffer bájt. A memóriába a regiszter mentést is beleszámoltam.
Azértt ilyen hosszú, mert xon/xoff-ot is tud. :)

Az egyik "aljához" javaslom PIC-re kipróbálni a CC5X fordítót. Kettő tapasztalat:

1. A legegyszerűbbnél összetettebb ANSI C szintaktikára is kiírja, hogy egyszerűsítsd le számára.
2. Nem gondolkozik, implementál. Konstans szorzásnál sem ügyeskedik, hanem berak egy szoftveres szorzót.

AVR-re a gcc már sokkal okosabb. Ez esetben igen kevés az a feladat, amikor assembly-t célszerű kézzel igazítani. Legutóbb talán a low speed (=1,5 Mbps) USB hardver támogatás nélküli szoftver implementációja esetén volt indokolt. --> https://www.obdev.at/products/vusb/index.html
De sok-sok éve van már USB-re hardvertámogatás a 8 bites mikrovezérlőkben is, ráadásul nem a low speed-re hanem legalább full speed-re (12 Mbps). Így már az ilyen programokat is tisztán C-ben lehet írni.

32 bites mikrovezérlők esetén szintén igen jól fordít a GCC.

Idők:

gcc -S --> assembly-t elemezhetsz ha érdekel illetve rövid kódrészt kell átnézned.
Vagy rutin elején elrakod a timer számlálóértékét, a rutin végén ismét kiolvasod. A különbözetet vagy időről időre a különbözetek maximumát megjeleníted.

x86/ARM linux esetén is ugyanez a módszer a bevált. Számoltasd ki a procival, mennyi idő alatt végzett: http://www.gnu.org/software/libc/manual/html_node/CPU-Time.html

Alaposságod ellenére inkább úgy hangzik, mint a problémák összefoglalója.
A CC5X fizetős, de csak az "aljára" jó. A CC8E meg a 18-as család egyes tagjaira. Tegyük fel, hogy ez a két fordító "egyforma".
Viszont a CC5X pont azt nem támogatja, amit használok!
Ugyanakkor szeretnék áttérni a kisebb eszközökről a 24-es családra. Ehhez megint nem jó a fenti fordító.
De azért, mert ajánlottad, megnézem közelebbről.

Szóval lefutottam az összes köröket, marad az asm. Méghozzá a gputils, mert folyamatosan frissítik/javítják a Microchip headerjeit. Sőt, itt a hupon is megtalálható az egyik fejlesztője, aki készségesen és azonnal javítja a hibát.

Ami a lényeg: Ha másik mikrokontrollert választok, nem szeretném néhány hónap alatt megint kitalálni, hogy ahhoz melyik fordítónak mi a hibája. A feladat, avagy a probléma megoldása általában a vezérlési szerkezet kitalálása. A példádban a szorzás megint egy olyan művelet, amit meg kell fontolni - hátha nincs is szükség rá. :)

A -s barátunk. :)

Futásidő mérésre kiváló az rtc. Pl. POWER processzoron, ott pontosabb. :)
Mikrogépen mást ajánlok - mivel hátha nincs kijelző se. ;)
Egy kimenetet ki kell nevezni triggernek, majd a kód előtt "set trigger", utána "reset trigger". A triggerre meg rá kell kötni egy ilyet, és látod a futásidőt +-83ns pontossággal.
Hasonló esetben, pl. I2C bus collision után, high priority interrupt közepén el lehetne rakni az állapotot, aztán kiírni... Helyette a felprogramozott soros port TX regiszterébe, majd TX lábáról egy csipesz az analizátorba+protokoll analizátor. Így azonnal olvasható a hibát tatalmazó regiszter értéke.
Ez azért hatékonyabb megoldás.

Off: Szemet szúrt a nicked! Én is műveltem hasonlót 3gj szárnyai alatt 5-6 évig. Voltam 3kgj, 2krv, 5bme, de úgy 80 körül abbahagytam.

Simán belefér bármi c-ben is. Használtam 16MHz-es atmega128rfa1-et 2MBaud-on is, bár ott csak annyi volt a feladat, hogy a rádión érkező adat, menjen át soros portra. Ennél mondjuk valamivel bonyolultabb, mert a rádiónak is van egy stack-je, meg a soros portnak is (utóbbi csak framing/escaping-et végez).
De az sscanf tényleg necces lehet, az nagyon általános célú, ennek megfelelően elég pazarló. De nem lepne meg, ha az is elég lenne itt.